├── .editorconfig ├── .gitattributes ├── .gitignore ├── .npmrc ├── .stylelintignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __tests__ ├── __snapshots__ │ ├── commenting.test.js.snap │ ├── functions.test.js.snap │ ├── index.test.js.snap │ ├── media-queries.test.js.snap │ ├── properties.test.js.snap │ ├── selectors-scss.test.js.snap │ ├── selectors.test.js.snap │ ├── structure.test.js.snap │ └── values.test.js.snap ├── commenting-invalid.css ├── commenting-valid.css ├── commenting.test.js ├── css-invalid.css ├── css-valid.css ├── functions-invalid.css ├── functions-valid.css ├── functions.test.js ├── index.test.js ├── media-queries-invalid.css ├── media-queries-valid.css ├── media-queries.test.js ├── properties-invalid.css ├── properties-valid.css ├── properties.test.js ├── scss-invalid.scss ├── scss-valid.scss ├── scss.test.js ├── selectors-invalid.css ├── selectors-invalid.scss ├── selectors-scss.test.js ├── selectors-valid.css ├── selectors-valid.scss ├── selectors.test.js ├── structure-invalid.css ├── structure-valid.css ├── structure.test.js ├── themes-valid.css ├── themes.test.js ├── values-invalid.css ├── values-valid.css ├── values.test.js ├── vendor-prefixes-valid.css └── vendor-prefixes.test.js ├── index.js ├── package.json ├── prettier.config.js └── scss.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | *-invalid.* 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | git: 2 | depth: 1 3 | 4 | branches: 5 | only: 6 | - master 7 | 8 | os: 9 | - linux 10 | - windows 11 | 12 | language: node_js 13 | 14 | cache: 15 | directories: 16 | - $HOME/.npm 17 | - node_modules 18 | 19 | node_js: 20 | - '10' 21 | - '12' 22 | 23 | before_install: 24 | - if [[ ("$TRAVIS_OS_NAME" == "linux") ]]; then npm install -g npm@latest; fi 25 | 26 | script: npm test 27 | 28 | notifications: 29 | slack: 30 | secure: Wx2BzF1JO9iUE6Wrf5lMzHHEtHf7+LT+/azLrODvLum97IL+Jj8K2LgFF+e6cEHBGpklwwaUH93sATFOH6vp7U0TF19dYBOs50iBMFeCT/hfv5nQaS8Eo6TWz9lBMQC6adXCEWyBgnyOlVL4/MOO1LlGwfWoGlfkpVrvJkke9vkEEQWUt2t78AL/baZX6Zv0Tvc7MbLzpVS8oHMAs3KtGX6hq1VoQ49QXTogQe+ezQe7CIhqvsGo56JvmEahAtfLycqVLx8pGzUzzVTfooCvIwhQZBTDn86MP4KMZYXGkGzW2dQexj0w2FvrBU19DSf4S6igvN3LgusqtludV0+XlWVZOOaM5Pe6ML+FxRSJjkFiBk+lUSuK5BdKQYHr1LnHDN30a0TSJyPX1aPY7vT7RPD5fglDAGNoK/2IkQ/uboZyXqApMTSm7cYuBbQNIMkUzOV7NF03FUCL2TyX0MM3mW32o0GQDYV/n42CSGHVmOPsvJNzMN2cspdDQLIRAlgih+0ZvHDd9rn+eHjgOYaHRBTMrB+iXJZvIj9HqO+W8tf+YUaRO6UDj4w2VErfTcax73d1W12KRXY2GRAAAFBBB1Dws8lVWs0gp5jjvk4OXQSrmDaR6bFW2QaFcilMupOfJydPbIhX0+FR1Arf6bXaCHspxIP4Mwzkiw8m4ZpHtck= 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 17.0.0 2 | 3 | - Updated: `stylelint-scss` to `3.17.2`. 4 | - Updated: `stylelint` to `13.0.0`. 5 | 6 | # 16.0.0 7 | 8 | - Fixed: `selector-class-pattern` rule regex to account for numerals, case detection, and ensure kebab-case over snake_case. 9 | - Fixed: `selector-id-pattern` rule regex to account for numerals, case detection, and ensure kebab-case over snake_case. 10 | - Updated: `stylelint-config-recommended-scss` to `4.1.0`. 11 | - Updated: `stylelint-find-rules` to `2.2.0`. 12 | - Updated: `stylelint-scss` to `3.13.0`. 13 | - Updated: `stylelint` to `11.0.0`. 14 | 15 | # 15.0.0 16 | 17 | - Added: NodeJS 12.x.x support. 18 | - Updated: `stylelint` to `11.0.0`. 19 | - Removed: `stylelint < 10.1.0` compatibility. 20 | - Updated: `stylelint-config-recommended` to `3.0.0`. 21 | - Updated: `stylelint-config-recommended-scss` to `4.0.0`. 22 | - Updated: Bump minimum Node.js required version to `10.0.0`. 23 | 24 | # 14.0.0 25 | 26 | - Updated: `stylelint` to `10.0.0`. 27 | - Updated: `stylelint-scss` to `3.6.0`. 28 | - Updated: `stylelint-config-recommended` to `2.2.0`. 29 | 30 | # 13.1.0 31 | 32 | - Added: Added SCSS _shared config_ `extends` tests. 33 | - Changed: `stylelint-config-wordpress/scss` now extends [`stylelint-config-recommended-scss`](https://github.com/kristerkari/stylelint-config-recommended-scss) (the net result of this change results in no rule changes for this SCSS config). 34 | - Updated: `stylelint-scss` to `3.3.0`. 35 | - Updated: `stylelint` to `9.5.0`. 36 | 37 | # 13.0.0 38 | 39 | - Added: stylelint `9.1.3` support. 40 | - Changed: Updated `stylelint` peer dependency version to `^9.1.3`. 41 | - Changed: Improved `no-duplicate-selectors` tests. 42 | - Removed: Jest snapshots. 43 | - Removed: `stylelint < 9.1.3` compatibility. 44 | - Updated: `selector-pseudo-element-colon-notation` to use `double` 45 | - Updated: `stylelint-config-recommended` to `2.1.0`. 46 | - Updated: `stylelint-scss` to `2.1.0`. 47 | - Updated: Bump minimum Node.js required version to `8.9.3`. 48 | 49 | # 12.0.0 50 | 51 | - Changed: `stylelint-config-wordpress` now extends [`stylelint-config-recommended`](https://github.com/stylelint/stylelint-config-recommended), which turns on the `at-rule-no-unknown`, `block-no-empty`, `comment-no-empty`, `declaration-block-no-ignored-properties`, `declaration-block-no-redundant-longhand-properties`, `font-family-no-duplicate-names`, `media-feature-name-no-unknown`, `no-empty-source` rule. These rules are part of stylelint's [possible errors](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md#possible-errors) rules. 52 | - Removed: `stylelint-scss < 1.5.1` compatibility. 53 | - Removed: Removed style guide docs. 54 | - Removed: `at-rule-no-unknown` custom `ignoreAtRules` options in `stylelint-config-wordpress/scss` shared config. 55 | - Added: `scss/at-rule-no-unknown` rule in `stylelint-config-wordpress/scss` shared config. 56 | - Added: NodeJS 8.x.x support. 57 | - Added: npm 5.x.x support. 58 | - Added: Jest snapshots to help detect and prevent regressions. 59 | 60 | # 11.0.0 61 | 62 | - Added: `declaration-property-unit-whitelist` rule to allow `px` and exclude `%` and `em` units in `line-height` values. 63 | - Changed: Relocated repo to https://github.com/WordPress-Coding-Standards. 64 | - Fixed: Include CSS config `at-rule-empty-line-before` rules in SCSS config. 65 | 66 | # 10.0.2 67 | 68 | - Added: Added `import` to `ignoreAtRules` option in `at-rule-empty-line-before` rule for SCSS config. 69 | 70 | # 10.0.1 71 | 72 | - Removed: `rule-non-nested-empty-line-before` rule from SCSS config. This rule is deprecated in stylelint v8, the new `rule-empty-line-before` rule already exists in the primary config. 73 | 74 | # 10.0.0 75 | 76 | - Added: `scss/selector-no-redundant-nesting-selector` rule in `stylelint-config-wordpress/scss` shared config. 77 | - Added: `selector-no-empty` rule. 78 | - Added: NodeJS 7.x.x support 79 | - Fixed: Added `stylelint-scss` plugin @if/@else placement rules. 80 | - Fixed: Ignore `relative` keyword names in `font-weight-notation` rule. 81 | - Fixed: Ignore proprietary `DXImageTransform.Microsoft` MS filters 82 | - Fixed: Removed `@debug` from `ignoreAtRules` array of `at-rule-no-unknown` rule in `stylelint-config-wordpress/scss` chared config. 83 | - Deprecated `blockless-group` option for `at-rule-empty-line-before` rule. Use the new `blockless-after-blockless` option instead. 84 | - Deprecated `media-feature-no-missing-punctuation` rule. 85 | - Deprecated `rule-nested-empty-line-before` and `rule-non-nested-empty-line-before` rules. Use the new `rule-empty-line-before` rule instead. 86 | - Deprecated `selector-no-empty` rule. 87 | - Refactor: Switch from AVA to Jest for tests. 88 | - Refactor: Switch from eslint-plugin-ava to eslint-plugin-jest. 89 | - Removed: `stylelint < 7.10.1` compatibility. 90 | - Removed: `stylelint-scss < 1.4.4` compatibility. 91 | - Removed: NodeJS 4.x support, `stylelint` and `stylelint-config-wordpress` now require NodeJS > 6.9.1 LTS or greater 92 | 93 | # 9.1.1 94 | 95 | - Fixed: Re-releasing failed npmjs.com 9.1.0 release as 9.1.1. 96 | 97 | # 9.1.0 98 | 99 | - Added: `stylelint-config-wordpress/scss` preset. 100 | 101 | # 9.0.0 102 | 103 | - Removed: `stylelint < 7.2.0` compatibility. 104 | - Removed: NodeJS 0.12.x support, `stylelint` and `stylelint-config-wordpress` now require NodeJS > 4.2.1 LTS or greater 105 | - Added: `at-rule-no-unknown` rule. 106 | - Added: `selector-attribute-quotes` rule. 107 | - Added: `font-weight-notation` rule. 108 | - Added: `max-line-length` rule. 109 | - Added: `property-no-unknown` rule. 110 | - Added: `selector-class-pattern` rule. 111 | - Added: `selector-id-pattern` rule. 112 | - Deprecated `no-missing-eof-newline` rule. Use the new `no-missing-end-of-source-newline` rule instead. 113 | - Fixed `font-family-name-quotes` test warning message in `values.js`. 114 | 115 | # 8.0.0 116 | 117 | - Removed: `stylelint < 6.6.0` compatibility. 118 | - Removed: `number-zero-length-no-unit` rule. 119 | - Added: `length-zero-no-unit` rule. 120 | - Added: `value-keyword-case` rule. 121 | 122 | # 7.1.1 123 | 124 | - Fixed: Re-releasing failed npmjs.com 7.0.0 release as 7.1.1. 125 | 126 | # 7.1.0 127 | 128 | - Fixed: `font-family-name-quotes` rule deprecated option `double-where-recommended` to new `always-where-recommended` option. 129 | - Fixed: `function-url-quotes` rule deprecated option `none` to new `never` option. 130 | - Removed: `stylelint < 6.5.1` compatibility. 131 | - Changed: Improved tests and documentation. 132 | - Added: `comment-empty-line-before` rule. 133 | 134 | # 7.0.0 135 | 136 | - Added: `keyframe-declaration-no-important` rule. 137 | - Added: `selector-pseudo-class-no-unknown` rule. 138 | - Added: `selector-pseudo-element-no-unknown` rule. 139 | - Added: `selector-type-no-unknown` rule. 140 | 141 | # 6.0.0 142 | 143 | - Added: `at-rule-name-space-after` rule. 144 | - Added: `no-extra-semicolons` rule. 145 | - Added: `selector-attribute-operator-space-after` rule. 146 | - Added: `selector-attribute-operator-space-before` rule. 147 | - Added: `selector-max-empty-liness` rule. 148 | 149 | # 5.0.0 150 | 151 | - Added: `at-rule-name-case` rule. 152 | - Added: `declaration-block-no-duplicate-properties` rule. 153 | - Added: `function-max-empty-lines` rule. 154 | - Added: `function-name-case` rule. 155 | - Added: `property-case` rule. 156 | - Added: `selector-attribute-brackets-space-inside` rule. 157 | - Added: `selector-pseudo-class-case` rule. 158 | - Added: `selector-pseudo-class-parentheses-space-inside` rule. 159 | - Added: `selector-pseudo-element-case` rule. 160 | - Added: `shorthand-property-no-redundant-values` rule. 161 | - Added: `unit-case` rule. 162 | - Added: `unit-no-unknown` rule. 163 | 164 | # 4.0.0 165 | 166 | - Removed: `stylelint < 5.2.0` compatibility. 167 | - Added: `at-rule-semicolon-newline-after` rule. 168 | - Added: `selector-type-case` rule. 169 | 170 | # 3.0.1 171 | 172 | - Added: `stylelint` version `^4.5.0` as a peer dependency to `peerDependencies` in `package.json` 173 | 174 | # 3.0.0 175 | 176 | - Removed: `stylelint < 4.5.0` compatibility. 177 | - Deprecated: `rule-no-shorthand-property-overrides` rule. Use the new `declaration-block-no-shorthand-property-overrides` rule instead. 178 | - Deprecated: `rule-trailing-semicolon` rule. Use the new `declaration-block-trailing-semicolon` rule instead. 179 | - Added: `color-named` rule. 180 | - Added: `declaration-block-no-shorthand-property-overrides` rule. 181 | - Added: `declaration-block-trailing-semicolon` rule. 182 | - Added: `string-no-newline` rule. 183 | 184 | # 2.1.0 185 | 186 | - Added: `max-empty-lines` rule, limits the number of adjacent empty lines to 2. 187 | - Changed: `rule-nested-empty-line-before` rule option `ignore: ["after-comment"]`. 188 | - Removed all vendor prefixes, lets autoprefixer handle vendor prefixes: 189 | - Removed: `at-rule-no-vendor-prefix` 190 | - Removed: `media-feature-name-no-vendor-prefix` 191 | - Removed: `property-no-vendor-prefix` 192 | - Removed: `selector-no-vendor-prefix` 193 | - Removed: `value-no-vendor-prefix` 194 | 195 | # 2.0.2 196 | 197 | - Fixed another npmjs.com release issue 198 | 199 | # 2.0.1 200 | 201 | - Fixed npmjs.com release 202 | 203 | # 2.0.0 204 | 205 | - Removed: `media-query-parentheses-space-inside` rule. 206 | - Removed: `stylelint < 4.3.4` compatibility. 207 | - Added: `font-family-name-quotes` rule with double quotes where recommended option. 208 | - Added: `media-feature-no-missing-punctuation` rule. 209 | - Added: `no-invalid-double-slash-comments` rule. 210 | 211 | # 1.1.1 212 | 213 | - Changed: `rule-non-nested-empty-line-before` with option `ignore: ["after-comment"],`. 214 | 215 | # 1.1.0 216 | 217 | - Added: `selector-pseudo-element-colon-notation` with option `single` 218 | 219 | # 1.0.1 220 | 221 | - Changed: config syntax. 222 | 223 | # 1.0.0 224 | 225 | - Removed: `stylelint < 3.0.0` compatibility. 226 | - Changed: renamed the `function-space-after` rule to `function-whitespace-after`. 227 | - Changed: `at-rule-empty-line-before` with option `ignore: ["after-comment"],`. 228 | - Changed: `declaration-colon-space-after` with option `always-single-line`. 229 | - Added: `declaration-colon-newline-after` with option `always-multi-line`. 230 | - Added: `function-linear-gradient-no-nonstandard-direction`. 231 | 232 | # 0.2.0 233 | 234 | - Fixed: No quotes for URLs -> `"function-url-quotes": [ 2, "none" ]`. 235 | 236 | # 0.1.0 237 | 238 | - Initial release. 239 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 stylelint 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### ⚠️ This package has been deprecated, please use @wordpress/stylelint-config or @wordpress/scripts ⚠️ 2 | 3 | # stylelint-config-wordpress 4 | [![NPM version](http://img.shields.io/npm/v/stylelint-config-wordpress.svg)](https://www.npmjs.org/package/stylelint-config-wordpress) [![Build Status](https://api.travis-ci.org/WordPress-Coding-Standards/stylelint-config-wordpress.svg?branch=master)](https://travis-ci.org/WordPress-Coding-Standards/stylelint-config-wordpress) 5 | 6 | > WordPress shareable config for stylelint. 7 | 8 | Configuration rules to ensure your CSS is compliant with the [WordPress CSS Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/css/). 9 | 10 | - `stylelint-config-wordpress` extends [`stylelint-config-recommended`](https://github.com/stylelint/stylelint-config-recommended) 11 | 12 | ## Table of Contents 13 | 14 | - [Installation](#installation) 15 | - [Usage](#usage) 16 | - [Presets](#presets) 17 | - [Extending the config](#extending-the-config) 18 | - [Changelog](#changelog) 19 | - [License](#license) 20 | 21 | ## Installation 22 | 23 | ```bash 24 | $ npm install stylelint-config-wordpress --save-dev 25 | ``` 26 | 27 | ## Usage 28 | 29 | If you've installed `stylelint-config-wordpress` locally within your project, just set your `stylelint` config to: 30 | 31 | ```json 32 | { 33 | "extends": "stylelint-config-wordpress" 34 | } 35 | ``` 36 | 37 | If you've globally installed `stylelint-config-wordpress` using the `-g` flag, then you'll need to use the absolute path to `stylelint-config-wordpress` in your config: 38 | 39 | ```json 40 | { 41 | "extends": "/absolute/path/to/stylelint-config-wordpress" 42 | } 43 | ``` 44 | 45 | ## Presets 46 | 47 | In addition to the default preset, there is also a SCSS preset. This preset extends both `stylelint-config-wordpress` and [`stylelint-config-recommended-scss`](https://github.com/kristerkari/stylelint-config-recommended-scss). 48 | 49 | ### SCSS 50 | 51 | ```json 52 | { 53 | "extends": [ 54 | "stylelint-config-wordpress/scss" 55 | ] 56 | } 57 | ``` 58 | 59 | ## Extending the config 60 | 61 | Simply add a `"rules"` key to your config and add your overrides there. 62 | 63 | For example, to change the `indentation` to four spaces and turn off the `number-leading-zero` rule: 64 | 65 | 66 | ```json 67 | { 68 | "extends": "stylelint-config-wordpress", 69 | "rules": { 70 | "indentation": 4, 71 | "number-leading-zero": null 72 | } 73 | } 74 | ``` 75 | 76 | ## [Changelog](CHANGELOG.md) 77 | 78 | ## [License](LICENSE) 79 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/commenting.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid commenting css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 1, 7 | "line": 9, 8 | "rule": "comment-empty-line-before", 9 | "severity": "error", 10 | "text": "Expected empty line before comment (comment-empty-line-before)", 11 | }, 12 | Object { 13 | "column": 1, 14 | "line": 18, 15 | "rule": "comment-empty-line-before", 16 | "severity": "error", 17 | "text": "Expected empty line before comment (comment-empty-line-before)", 18 | }, 19 | Object { 20 | "column": 131, 21 | "line": 24, 22 | "rule": "max-line-length", 23 | "severity": "error", 24 | "text": "Expected line length to be no more than 80 characters (max-line-length)", 25 | }, 26 | ] 27 | `; 28 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/functions.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid functions css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 9, 7 | "line": 4, 8 | "rule": "function-name-case", 9 | "severity": "error", 10 | "text": "Expected \\"Calc\\" to be \\"calc\\" (function-name-case)", 11 | }, 12 | ] 13 | `; 14 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 7, 7 | "line": 2, 8 | "rule": "number-leading-zero", 9 | "severity": "error", 10 | "text": "Expected a leading zero (number-leading-zero)", 11 | }, 12 | ] 13 | `; 14 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/media-queries.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid media queries css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 1, 7 | "line": 31, 8 | "rule": "at-rule-no-unknown", 9 | "severity": "error", 10 | "text": "Unexpected unknown at-rule \\"@mdia\\" (at-rule-no-unknown)", 11 | }, 12 | Object { 13 | "column": 26, 14 | "line": 1, 15 | "rule": "media-feature-colon-space-after", 16 | "severity": "error", 17 | "text": "Expected single space after \\":\\" (media-feature-colon-space-after)", 18 | }, 19 | Object { 20 | "column": 27, 21 | "line": 6, 22 | "rule": "media-feature-colon-space-after", 23 | "severity": "error", 24 | "text": "Expected single space after \\":\\" (media-feature-colon-space-after)", 25 | }, 26 | Object { 27 | "column": 27, 28 | "line": 6, 29 | "rule": "media-feature-colon-space-before", 30 | "severity": "error", 31 | "text": "Unexpected whitespace before \\":\\" (media-feature-colon-space-before)", 32 | }, 33 | Object { 34 | "column": 17, 35 | "line": 11, 36 | "rule": "media-feature-name-no-unknown", 37 | "severity": "error", 38 | "text": "Unexpected unknown media feature name \\"max-width 699px\\" (media-feature-name-no-unknown)", 39 | }, 40 | Object { 41 | "column": 28, 42 | "line": 16, 43 | "rule": "media-feature-range-operator-space-after", 44 | "severity": "error", 45 | "text": "Expected single space after range operator (media-feature-range-operator-space-after)", 46 | }, 47 | Object { 48 | "column": 29, 49 | "line": 21, 50 | "rule": "media-feature-range-operator-space-after", 51 | "severity": "error", 52 | "text": "Expected single space after range operator (media-feature-range-operator-space-after)", 53 | }, 54 | Object { 55 | "column": 25, 56 | "line": 16, 57 | "rule": "media-feature-range-operator-space-before", 58 | "severity": "error", 59 | "text": "Expected single space before range operator (media-feature-range-operator-space-before)", 60 | }, 61 | Object { 62 | "column": 25, 63 | "line": 26, 64 | "rule": "media-feature-range-operator-space-before", 65 | "severity": "error", 66 | "text": "Expected single space before range operator (media-feature-range-operator-space-before)", 67 | }, 68 | Object { 69 | "column": 27, 70 | "line": 36, 71 | "rule": "media-query-list-comma-space-before", 72 | "severity": "error", 73 | "text": "Unexpected whitespace before \\",\\" (media-query-list-comma-space-before)", 74 | }, 75 | Object { 76 | "column": 27, 77 | "line": 40, 78 | "rule": "media-query-list-comma-space-before", 79 | "severity": "error", 80 | "text": "Unexpected whitespace before \\",\\" (media-query-list-comma-space-before)", 81 | }, 82 | ] 83 | `; 84 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/properties.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid properties css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 13, 7 | "line": 2, 8 | "rule": "color-hex-case", 9 | "severity": "error", 10 | "text": "Expected \\"#FFFFFF\\" to be \\"#ffffff\\" (color-hex-case)", 11 | }, 12 | Object { 13 | "column": 13, 14 | "line": 2, 15 | "rule": "color-hex-length", 16 | "severity": "error", 17 | "text": "Expected \\"#FFFFFF\\" to be \\"#FFF\\" (color-hex-length)", 18 | }, 19 | Object { 20 | "column": 2, 21 | "line": 5, 22 | "rule": "declaration-block-no-shorthand-property-overrides", 23 | "severity": "error", 24 | "text": "Unexpected shorthand \\"margin\\" after \\"margin-left\\" (declaration-block-no-shorthand-property-overrides)", 25 | }, 26 | Object { 27 | "column": 13, 28 | "line": 2, 29 | "rule": "declaration-colon-space-after", 30 | "severity": "error", 31 | "text": "Expected single space after \\":\\" with a single-line declaration (declaration-colon-space-after)", 32 | }, 33 | Object { 34 | "column": 2, 35 | "line": 6, 36 | "rule": "property-no-unknown", 37 | "severity": "error", 38 | "text": "Unexpected unknown property \\"argin\\" (property-no-unknown)", 39 | }, 40 | Object { 41 | "column": 15, 42 | "line": 4, 43 | "rule": "unit-case", 44 | "severity": "error", 45 | "text": "Expected \\"PX\\" to be \\"px\\" (unit-case)", 46 | }, 47 | Object { 48 | "column": 11, 49 | "line": 3, 50 | "rule": "value-keyword-case", 51 | "severity": "error", 52 | "text": "Expected \\"BLOCK\\" to be \\"block\\" (value-keyword-case)", 53 | }, 54 | ] 55 | `; 56 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/selectors-scss.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid selectors scss snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 2, 7 | "line": 3, 8 | "rule": "scss/selector-no-redundant-nesting-selector", 9 | "severity": "error", 10 | "text": "Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)", 11 | }, 12 | Object { 13 | "column": 2, 14 | "line": 10, 15 | "rule": "scss/selector-no-redundant-nesting-selector", 16 | "severity": "error", 17 | "text": "Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)", 18 | }, 19 | Object { 20 | "column": 2, 21 | "line": 17, 22 | "rule": "scss/selector-no-redundant-nesting-selector", 23 | "severity": "error", 24 | "text": "Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)", 25 | }, 26 | Object { 27 | "column": 2, 28 | "line": 24, 29 | "rule": "scss/selector-no-redundant-nesting-selector", 30 | "severity": "error", 31 | "text": "Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)", 32 | }, 33 | Object { 34 | "column": 2, 35 | "line": 31, 36 | "rule": "scss/selector-no-redundant-nesting-selector", 37 | "severity": "error", 38 | "text": "Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)", 39 | }, 40 | Object { 41 | "column": 10, 42 | "line": 31, 43 | "rule": "selector-pseudo-element-colon-notation", 44 | "severity": "error", 45 | "text": "Expected double colon pseudo-element notation (selector-pseudo-element-colon-notation)", 46 | }, 47 | ] 48 | `; 49 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/selectors.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid selectors css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 15, 7 | "line": 18, 8 | "rule": "declaration-property-unit-allowed-list", 9 | "severity": "error", 10 | "text": "Unexpected unit \\"%\\" for property \\"line-height\\" (declaration-property-unit-allowed-list)", 11 | }, 12 | Object { 13 | "column": 1, 14 | "line": 25, 15 | "rule": "selector-class-pattern", 16 | "severity": "error", 17 | "text": "Selector should use lowercase and separate words with hyphens (selector-class-pattern)", 18 | }, 19 | Object { 20 | "column": 1, 21 | "line": 1, 22 | "rule": "selector-id-pattern", 23 | "severity": "error", 24 | "text": "Selector should use lowercase and separate words with hyphens (selector-id-pattern)", 25 | }, 26 | Object { 27 | "column": 1, 28 | "line": 5, 29 | "rule": "selector-id-pattern", 30 | "severity": "error", 31 | "text": "Selector should use lowercase and separate words with hyphens (selector-id-pattern)", 32 | }, 33 | Object { 34 | "column": 4, 35 | "line": 9, 36 | "rule": "selector-id-pattern", 37 | "severity": "error", 38 | "text": "Selector should use lowercase and separate words with hyphens (selector-id-pattern)", 39 | }, 40 | Object { 41 | "column": 1, 42 | "line": 21, 43 | "rule": "selector-id-pattern", 44 | "severity": "error", 45 | "text": "Selector should use lowercase and separate words with hyphens (selector-id-pattern)", 46 | }, 47 | Object { 48 | "column": 10, 49 | "line": 29, 50 | "rule": "selector-pseudo-element-colon-notation", 51 | "severity": "error", 52 | "text": "Expected double colon pseudo-element notation (selector-pseudo-element-colon-notation)", 53 | }, 54 | Object { 55 | "column": 12, 56 | "line": 17, 57 | "rule": "string-quotes", 58 | "severity": "error", 59 | "text": "Expected double quotes (string-quotes)", 60 | }, 61 | ] 62 | `; 63 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/structure.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid structure css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 45, 7 | "line": 7, 8 | "rule": "block-closing-brace-newline-before", 9 | "severity": "error", 10 | "text": "Expected newline before \\"}\\" (block-closing-brace-newline-before)", 11 | }, 12 | Object { 13 | "column": 14, 14 | "line": 7, 15 | "rule": "block-opening-brace-newline-after", 16 | "severity": "error", 17 | "text": "Expected newline after \\"{\\" (block-opening-brace-newline-after)", 18 | }, 19 | Object { 20 | "column": 32, 21 | "line": 7, 22 | "rule": "declaration-block-semicolon-newline-after", 23 | "severity": "error", 24 | "text": "Expected newline after \\";\\" (declaration-block-semicolon-newline-after)", 25 | }, 26 | Object { 27 | "column": 12, 28 | "line": 1, 29 | "rule": "selector-list-comma-newline-after", 30 | "severity": "error", 31 | "text": "Expected newline after \\",\\" (selector-list-comma-newline-after)", 32 | }, 33 | Object { 34 | "column": 25, 35 | "line": 1, 36 | "rule": "selector-list-comma-newline-after", 37 | "severity": "error", 38 | "text": "Expected newline after \\",\\" (selector-list-comma-newline-after)", 39 | }, 40 | Object { 41 | "column": 3, 42 | "line": 4, 43 | "rule": "indentation", 44 | "severity": "error", 45 | "text": "Expected indentation of 0 tabs (indentation)", 46 | }, 47 | Object { 48 | "column": 3, 49 | "line": 2, 50 | "rule": "indentation", 51 | "severity": "error", 52 | "text": "Expected indentation of 1 tab (indentation)", 53 | }, 54 | Object { 55 | "column": 3, 56 | "line": 3, 57 | "rule": "indentation", 58 | "severity": "error", 59 | "text": "Expected indentation of 1 tab (indentation)", 60 | }, 61 | ] 62 | `; 63 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/values.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`flags warnings with invalid values css snapshot matches warnings 1`] = ` 4 | Array [ 5 | Object { 6 | "column": 16, 7 | "line": 2, 8 | "rule": "declaration-block-trailing-semicolon", 9 | "severity": "error", 10 | "text": "Expected a trailing semicolon (declaration-block-trailing-semicolon)", 11 | }, 12 | Object { 13 | "column": 13, 14 | "line": 2, 15 | "rule": "declaration-colon-space-after", 16 | "severity": "error", 17 | "text": "Expected single space after \\":\\" with a single-line declaration (declaration-colon-space-after)", 18 | }, 19 | Object { 20 | "column": 15, 21 | "line": 12, 22 | "rule": "declaration-property-unit-allowed-list", 23 | "severity": "error", 24 | "text": "Unexpected unit \\"em\\" for property \\"line-height\\" (declaration-property-unit-allowed-list)", 25 | }, 26 | Object { 27 | "column": 15, 28 | "line": 10, 29 | "rule": "font-family-name-quotes", 30 | "severity": "error", 31 | "text": "Expected quotes around \\"Times New Roman\\" (font-family-name-quotes)", 32 | }, 33 | Object { 34 | "column": 15, 35 | "line": 11, 36 | "rule": "font-weight-notation", 37 | "severity": "error", 38 | "text": "Expected numeric font-weight notation (font-weight-notation)", 39 | }, 40 | Object { 41 | "column": 11, 42 | "line": 6, 43 | "rule": "length-zero-no-unit", 44 | "severity": "error", 45 | "text": "Unexpected unit (length-zero-no-unit)", 46 | }, 47 | Object { 48 | "column": 15, 49 | "line": 6, 50 | "rule": "length-zero-no-unit", 51 | "severity": "error", 52 | "text": "Unexpected unit (length-zero-no-unit)", 53 | }, 54 | Object { 55 | "column": 24, 56 | "line": 6, 57 | "rule": "length-zero-no-unit", 58 | "severity": "error", 59 | "text": "Unexpected unit (length-zero-no-unit)", 60 | }, 61 | Object { 62 | "column": 1, 63 | "line": 15, 64 | "rule": "no-duplicate-selectors", 65 | "severity": "error", 66 | "text": "Unexpected duplicate selector \\".selector\\", first used at line 1 (no-duplicate-selectors)", 67 | }, 68 | ] 69 | `; 70 | -------------------------------------------------------------------------------- /__tests__/commenting-invalid.css: -------------------------------------------------------------------------------- 1 | /** 2 | * #.# Section title 3 | * 4 | * Description of section, whether or not it has media queries, etc. 5 | */ 6 | .selector { 7 | float: left; 8 | } 9 | /** 10 | * #.# Another section title 11 | * 12 | * Description of section, whether or not it has media queries, long comments 13 | * should manually break the line length at 80 characters. 14 | */ 15 | .another-selector { 16 | float: right; 17 | } 18 | /* This is a comment about this selector */ 19 | .one-more-another-selector { 20 | position: absolute; 21 | top: 0 !important; /* I should explain why this is so !important */ 22 | } 23 | 24 | /* Comments shouldn't have a line length greater than 80 characters, they should manually break the line length at 80 characters */ 25 | -------------------------------------------------------------------------------- /__tests__/commenting-valid.css: -------------------------------------------------------------------------------- 1 | /** 2 | * #.# Section title 3 | * 4 | * Description of section, whether or not it has media queries, etc. 5 | */ 6 | 7 | .selector { 8 | float: left; 9 | } 10 | 11 | 12 | /** 13 | * #.# Another section title 14 | * 15 | * Description of section, whether or not it has media queries, long comments 16 | * should manually break the line length at 80 characters. 17 | */ 18 | 19 | .another-selector { 20 | float: right; 21 | } 22 | 23 | /* This is a comment about this selector */ 24 | .one-more-selector { 25 | position: absolute; 26 | top: 0 !important; /* I should explain why this is so !important */ 27 | } 28 | 29 | /* Long comments should manually break the line length at 80 characters. */ 30 | -------------------------------------------------------------------------------- /__tests__/commenting.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/commenting-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( 8 | './__tests__/commenting-invalid.css', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid commenting css', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validCss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid commenting css', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidCss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 3 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/css-invalid.css: -------------------------------------------------------------------------------- 1 | a { 2 | top: .2em; 3 | } 4 | -------------------------------------------------------------------------------- /__tests__/css-valid.css: -------------------------------------------------------------------------------- 1 | a { 2 | top: 0.2em; 3 | } 4 | -------------------------------------------------------------------------------- /__tests__/functions-invalid.css: -------------------------------------------------------------------------------- 1 | /* function-name-case */ 2 | 3 | a { 4 | width: Calc(5% - 10em); 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/functions-valid.css: -------------------------------------------------------------------------------- 1 | /* function-name-case */ 2 | 3 | a { 4 | width: calc(5% - 10em); 5 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#1e8cbe", endColorstr="#0074a2", GradientType=0); 6 | filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100); 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/functions.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/functions-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( 8 | './__tests__/functions-invalid.css', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid functions css', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validCss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid functions css', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidCss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 1 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/css-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( './__tests__/css-invalid.css', 'utf-8' ); 8 | 9 | describe( 'flags no warnings with valid css', () => { 10 | let result; 11 | 12 | beforeEach( () => { 13 | result = stylelint.lint( { 14 | code: validCss, 15 | config, 16 | } ); 17 | } ); 18 | 19 | it( 'did not error', () => { 20 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 21 | } ); 22 | 23 | it( 'flags no warnings', () => { 24 | return result.then( ( data ) => 25 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 26 | ); 27 | } ); 28 | } ); 29 | 30 | describe( 'flags warnings with invalid css', () => { 31 | let result; 32 | 33 | beforeEach( () => { 34 | result = stylelint.lint( { 35 | code: invalidCss, 36 | config, 37 | } ); 38 | } ); 39 | 40 | it( 'did error', () => { 41 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 42 | } ); 43 | 44 | it( 'flags correct number of warnings', () => { 45 | return result.then( ( data ) => 46 | expect( data.results[ 0 ].warnings ).toHaveLength( 1 ) 47 | ); 48 | } ); 49 | 50 | it( 'snapshot matches warnings', () => { 51 | return result.then( ( data ) => 52 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 53 | ); 54 | } ); 55 | } ); 56 | -------------------------------------------------------------------------------- /__tests__/media-queries-invalid.css: -------------------------------------------------------------------------------- 1 | @media all and (max-width:699px) { 2 | 3 | /* Your selectors */ 4 | } 5 | 6 | @media all and (max-width :699px) { 7 | 8 | /* Your selectors */ 9 | } 10 | 11 | @media all and (max-width 699px) { 12 | 13 | /* Your selectors */ 14 | } 15 | 16 | @media all and (max-width>=699px) { 17 | 18 | /* Your selectors */ 19 | } 20 | 21 | @media all and (max-width >=699px) { 22 | 23 | /* Your selectors */ 24 | } 25 | 26 | @media all and (max-width>= 699px) { 27 | 28 | /* Your selectors */ 29 | } 30 | 31 | @mdia all and (max-width>= 699px) { 32 | 33 | /* Your selectors */ 34 | } 35 | 36 | @media screen and (color) , projection and (color) { 37 | top: 0.2em; 38 | } 39 | 40 | @media screen and (color) , 41 | projection and (color) { 42 | top: 0.2em; 43 | } 44 | -------------------------------------------------------------------------------- /__tests__/media-queries-valid.css: -------------------------------------------------------------------------------- 1 | @media all and (max-width: 699px) and (min-width: 520px) { 2 | 3 | /* Your selectors */ 4 | } 5 | 6 | @media screen and (color), 7 | projection and (color) { 8 | top: 0.2em; 9 | } 10 | 11 | @media screen and (color), projection and (color) { 12 | top: 0.2em; 13 | } 14 | -------------------------------------------------------------------------------- /__tests__/media-queries.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( 7 | './__tests__/media-queries-valid.css', 8 | 'utf-8' 9 | ), 10 | invalidCss = fs.readFileSync( 11 | './__tests__/media-queries-invalid.css', 12 | 'utf-8' 13 | ); 14 | 15 | describe( 'flags no warnings with valid media queries css', () => { 16 | let result; 17 | 18 | beforeEach( () => { 19 | result = stylelint.lint( { 20 | code: validCss, 21 | config, 22 | } ); 23 | } ); 24 | 25 | it( 'did not error', () => { 26 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 27 | } ); 28 | 29 | it( 'flags no warnings', () => { 30 | return result.then( ( data ) => 31 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 32 | ); 33 | } ); 34 | } ); 35 | 36 | describe( 'flags warnings with invalid media queries css', () => { 37 | let result; 38 | 39 | beforeEach( () => { 40 | result = stylelint.lint( { 41 | code: invalidCss, 42 | config, 43 | } ); 44 | } ); 45 | 46 | it( 'did error', () => { 47 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 48 | } ); 49 | 50 | it( 'flags correct number of warnings', () => { 51 | return result.then( ( data ) => 52 | expect( data.results[ 0 ].warnings ).toHaveLength( 11 ) 53 | ); 54 | } ); 55 | 56 | it( 'snapshot matches warnings', () => { 57 | return result.then( ( data ) => 58 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 59 | ); 60 | } ); 61 | } ); 62 | -------------------------------------------------------------------------------- /__tests__/properties-invalid.css: -------------------------------------------------------------------------------- 1 | #selector-1 { 2 | background:#FFFFFF; 3 | display: BLOCK; 4 | margin-left: 20PX; 5 | margin: 0; 6 | argin: 20px; 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/properties-valid.css: -------------------------------------------------------------------------------- 1 | #selector-1 { 2 | background: #fff; 3 | display: block; 4 | margin: 0; 5 | margin-left: 20px; 6 | } 7 | -------------------------------------------------------------------------------- /__tests__/properties.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/properties-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( 8 | './__tests__/properties-invalid.css', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid properties css', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validCss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid properties css', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidCss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 7 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/scss-invalid.scss: -------------------------------------------------------------------------------- 1 | @unknown { 2 | display: block; 3 | } 4 | 5 | a { 6 | 7 | @debug 1; 8 | } 9 | 10 | @if $foo == block { 11 | display: block; 12 | } 13 | 14 | @else{ 15 | display: inline-block; 16 | } 17 | 18 | b { 19 | 20 | @include foo; 21 | 22 | @include bar; 23 | } 24 | 25 | p { 26 | 27 | /* Test `stylelint-config-recommended` inherited `no-extra-semicolons` rule */ 28 | @include foo;; 29 | 30 | /* Test `stylelint-config-wordpress` inherited `number-leading-zero` rule */ 31 | top: .2em; 32 | } 33 | -------------------------------------------------------------------------------- /__tests__/scss-valid.scss: -------------------------------------------------------------------------------- 1 | @import "path/to/foo.scss"; 2 | 3 | @function fooBar { 4 | 5 | @return 1; 6 | } 7 | 8 | @mixin foo { 9 | 10 | @content; 11 | } 12 | 13 | $map: ( 14 | "foo": 1, 15 | "bar": 2, 16 | "baz": 3 17 | ); 18 | 19 | @if $foo == block { 20 | display: block; 21 | } @else { 22 | display: inline-block; 23 | } 24 | 25 | @import "../some/url"; 26 | @import "../another/url"; 27 | 28 | b { 29 | 30 | @include foo; 31 | @include bar; 32 | } 33 | -------------------------------------------------------------------------------- /__tests__/scss.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../scss.js' ), 5 | stylelint = require( 'stylelint' ), 6 | validScss = fs.readFileSync( './__tests__/scss-valid.scss', 'utf-8' ), 7 | invalidScss = fs.readFileSync( './__tests__/scss-invalid.scss', 'utf-8' ); 8 | 9 | describe( 'flags no warnings with valid scss', () => { 10 | let result; 11 | 12 | beforeEach( () => { 13 | result = stylelint.lint( { 14 | code: validScss, 15 | config, 16 | } ); 17 | } ); 18 | 19 | it( 'did not error', () => { 20 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 21 | } ); 22 | 23 | it( 'flags no warnings', () => { 24 | return result.then( ( data ) => 25 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 26 | ); 27 | } ); 28 | } ); 29 | 30 | describe( 'flags warnings with invalid scss', () => { 31 | let result; 32 | 33 | beforeEach( () => { 34 | result = stylelint.lint( { 35 | code: invalidScss, 36 | config, 37 | } ); 38 | } ); 39 | 40 | it( 'did error', () => { 41 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 42 | } ); 43 | 44 | it( 'flags correct number of warnings', () => { 45 | return result.then( ( data ) => 46 | expect( data.results[ 0 ].warnings ).toHaveLength( 8 ) 47 | ); 48 | } ); 49 | 50 | // ToDo: Fix snapshot, as results differ between Node.js v10 & v12 51 | // it( 'snapshot matches warnings', () => { 52 | // return result.then( ( data ) => ( 53 | // expect( data.results[ 0 ].warnings ).toMatchSnapshot() 54 | // ) ); 55 | // } ); 56 | } ); 57 | -------------------------------------------------------------------------------- /__tests__/selectors-invalid.css: -------------------------------------------------------------------------------- 1 | #commentForm { /* Avoid camelcase. */ 2 | margin: 0; 3 | } 4 | 5 | #comment_form { /* Avoid underscores. */ 6 | margin: 0; 7 | } 8 | 9 | div#comment_form { /* Avoid over-qualification. */ 10 | margin: 0; 11 | } 12 | 13 | #c1-xr { /* What is a c1-xr?! Use a better name. */ 14 | margin: 0; 15 | } 16 | 17 | input[type='text'] { /* Should be [type="text"] */ 18 | line-height: 110% /* Also doubly incorrect */ 19 | } 20 | 21 | #Selector { 22 | color: #000; 23 | } 24 | 25 | .selectorA { 26 | color: #000; 27 | } 28 | 29 | .selector:after { 30 | color: #000; 31 | } 32 | -------------------------------------------------------------------------------- /__tests__/selectors-invalid.scss: -------------------------------------------------------------------------------- 1 | .foo { 2 | 3 | & > .bar { 4 | margin: 0; 5 | } 6 | } 7 | 8 | a { 9 | 10 | & a { 11 | margin: 0; 12 | } 13 | } 14 | 15 | div { 16 | 17 | & > a { 18 | margin: 0; 19 | } 20 | } 21 | 22 | p { 23 | 24 | & .class { 25 | margin: 0; 26 | } 27 | } 28 | 29 | span { 30 | 31 | & .class:after { 32 | margin: 0; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /__tests__/selectors-scss.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../scss.js' ), 5 | stylelint = require( 'stylelint' ), 6 | validScss = fs.readFileSync( './__tests__/selectors-valid.scss', 'utf-8' ), 7 | invalidScss = fs.readFileSync( 8 | './__tests__/selectors-invalid.scss', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid selectors scss', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validScss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid selectors scss', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidScss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 6 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/selectors-valid.css: -------------------------------------------------------------------------------- 1 | #comment-form { 2 | margin: 1em 0; 3 | } 4 | 5 | input[type="text"] { 6 | line-height: 1.1; 7 | } 8 | 9 | .selector::after { 10 | color: #000; 11 | } 12 | 13 | .selector-class { 14 | color: #000; 15 | } 16 | 17 | #selector-id { 18 | color: #000; 19 | } 20 | -------------------------------------------------------------------------------- /__tests__/selectors-valid.scss: -------------------------------------------------------------------------------- 1 | .foo { 2 | 3 | > .bar { 4 | margin: 0; 5 | } 6 | } 7 | 8 | a { 9 | 10 | &.foo { 11 | margin: 0; 12 | } 13 | } 14 | 15 | div { 16 | 17 | .foo > & { 18 | margin: 0; 19 | } 20 | } 21 | 22 | p { 23 | 24 | &, 25 | .foo, 26 | .baz { 27 | margin: 0; 28 | } 29 | } 30 | 31 | span { 32 | 33 | &, 34 | .foo::after { 35 | color: #000; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /__tests__/selectors.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/selectors-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( 8 | './__tests__/selectors-invalid.css', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid selectors css', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validCss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid selectors css', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidCss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 8 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/structure-invalid.css: -------------------------------------------------------------------------------- 1 | #selector-1, #selector-2, #selector-3 { 2 | background: #fff; 3 | color: #000; 4 | } 5 | 6 | 7 | #selector-1 { background: #fff; color: #000; } 8 | -------------------------------------------------------------------------------- /__tests__/structure-valid.css: -------------------------------------------------------------------------------- 1 | #selector-1, 2 | #selector-2, 3 | #selector-3 { 4 | background: #fff; 5 | color: #000; 6 | } 7 | 8 | #selector-4 { 9 | background: #fff; 10 | color: #000; 11 | } 12 | 13 | h1, 14 | .heading-size-1 { 15 | background: #fff; 16 | color: #000; 17 | } 18 | 19 | h2, 20 | .heading-size-2 { 21 | background: #fff; 22 | color: #000; 23 | } 24 | 25 | h3, 26 | .heading-size-3 { 27 | background: #fff; 28 | color: #000; 29 | } 30 | -------------------------------------------------------------------------------- /__tests__/structure.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/structure-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( 8 | './__tests__/structure-invalid.css', 9 | 'utf-8' 10 | ); 11 | 12 | describe( 'flags no warnings with valid structure css', () => { 13 | let result; 14 | 15 | beforeEach( () => { 16 | result = stylelint.lint( { 17 | code: validCss, 18 | config, 19 | } ); 20 | } ); 21 | 22 | it( 'did not error', () => { 23 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 24 | } ); 25 | 26 | it( 'flags no warnings', () => { 27 | return result.then( ( data ) => 28 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 29 | ); 30 | } ); 31 | } ); 32 | 33 | describe( 'flags warnings with invalid structure css', () => { 34 | let result; 35 | 36 | beforeEach( () => { 37 | result = stylelint.lint( { 38 | code: invalidCss, 39 | config, 40 | } ); 41 | } ); 42 | 43 | it( 'did error', () => { 44 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 45 | } ); 46 | 47 | it( 'flags correct number of warnings', () => { 48 | return result.then( ( data ) => 49 | expect( data.results[ 0 ].warnings ).toHaveLength( 8 ) 50 | ); 51 | } ); 52 | 53 | it( 'snapshot matches warnings', () => { 54 | return result.then( ( data ) => 55 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 56 | ); 57 | } ); 58 | } ); 59 | -------------------------------------------------------------------------------- /__tests__/themes-valid.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Twenty Ten 3 | Theme URI: https://wordpress.org/themes/twentyten/themes/twentyten/themes/twentyten/themes/twentyten/ 4 | Description: The 2010 theme for WordPress is stylish, customizable, simple, and readable -- make it yours with a custom menu, header image, and background. Twenty Ten supports six widgetized areas (two in the sidebar, four in the footer) and featured images (thumbnails for gallery posts and custom header images for posts and pages). It includes stylesheets for print and the admin Visual Editor, special styles for posts in the "Asides" and "Gallery" categories, and has an optional one-column page template that removes the sidebar. 5 | Author: the WordPress team 6 | Author URI: https://wordpress.org/ 7 | Version: 2.3 8 | License: GNU General Public License v2 or later 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | Tags: blog, two-columns, custom-header, custom-background, threaded-comments, sticky-post, translation-ready, microformats, rtl-language-support, editor-style, custom-menu, flexible-header, featured-images, footer-widgets, featured-image-header 11 | Text Domain: twentyten 12 | */ 13 | 14 | a { 15 | top: 0.2em; 16 | } 17 | -------------------------------------------------------------------------------- /__tests__/themes.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/themes-valid.css', 'utf-8' ); 7 | 8 | describe( 'flags no warnings with valid css', () => { 9 | let result; 10 | 11 | beforeEach( () => { 12 | result = stylelint.lint( { 13 | code: validCss, 14 | config, 15 | } ); 16 | } ); 17 | 18 | it( 'did not error', () => { 19 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 20 | } ); 21 | 22 | it( 'flags no warnings', () => { 23 | return result.then( ( data ) => 24 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 25 | ); 26 | } ); 27 | } ); 28 | -------------------------------------------------------------------------------- /__tests__/values-invalid.css: -------------------------------------------------------------------------------- 1 | .selector { /* Avoid missing space and semicolon */ 2 | background:#fff 3 | } 4 | 5 | .another-selector { /* Avoid adding a unit on a zero value */ 6 | margin: 0px 0px 20px 0px; 7 | } 8 | 9 | .one-more-selector { 10 | font-family: Times New Roman, serif; /* Quote font names when required */ 11 | font-weight: bold; /* Avoid named font weights */ 12 | line-height: 1.4em; 13 | } 14 | 15 | .selector { /* Avoid duplicate selectors */ 16 | background: #fff; 17 | } 18 | -------------------------------------------------------------------------------- /__tests__/values-valid.css: -------------------------------------------------------------------------------- 1 | .selector { /* Correct usage of quotes */ 2 | background-image: url(images/bg.png); 3 | font-family: "Helvetica Neue", sans-serif; 4 | font-weight: 700; 5 | line-height: 14px; 6 | } 7 | 8 | .another-selector { /* Correct usage of zero values */ 9 | font-family: Georgia, serif; 10 | font-weight: bolder; /* Ignore relative font weights */ 11 | line-height: 1.4; 12 | text-shadow: 13 | 0 -1px 0 rgba(0, 0, 0, 0.5), 14 | 0 1px 0 #fff; 15 | } 16 | -------------------------------------------------------------------------------- /__tests__/values.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( './__tests__/values-valid.css', 'utf-8' ), 7 | invalidCss = fs.readFileSync( './__tests__/values-invalid.css', 'utf-8' ); 8 | 9 | describe( 'flags no warnings with valid values css', () => { 10 | let result; 11 | 12 | beforeEach( () => { 13 | result = stylelint.lint( { 14 | code: validCss, 15 | config, 16 | } ); 17 | } ); 18 | 19 | it( 'did not error', () => { 20 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 21 | } ); 22 | 23 | it( 'flags no warnings', () => { 24 | return result.then( ( data ) => 25 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 26 | ); 27 | } ); 28 | } ); 29 | 30 | describe( 'flags warnings with invalid values css', () => { 31 | let result; 32 | 33 | beforeEach( () => { 34 | result = stylelint.lint( { 35 | code: invalidCss, 36 | config, 37 | } ); 38 | } ); 39 | 40 | it( 'did error', () => { 41 | return result.then( ( data ) => expect( data.errored ).toBeTruthy() ); 42 | } ); 43 | 44 | it( 'flags correct number of warnings', () => { 45 | return result.then( ( data ) => 46 | expect( data.results[ 0 ].warnings ).toHaveLength( 9 ) 47 | ); 48 | } ); 49 | 50 | it( 'snapshot matches warnings', () => { 51 | return result.then( ( data ) => 52 | expect( data.results[ 0 ].warnings ).toMatchSnapshot() 53 | ); 54 | } ); 55 | } ); 56 | -------------------------------------------------------------------------------- /__tests__/vendor-prefixes-valid.css: -------------------------------------------------------------------------------- 1 | .sample-output { 2 | -webkit-box-shadow: inset 0 0 1px 1px #eee; 3 | -moz-box-shadow: inset 0 0 1px 1px #eee; 4 | box-shadow: inset 0 0 1px 1px #eee; 5 | } 6 | -------------------------------------------------------------------------------- /__tests__/vendor-prefixes.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require( 'fs' ), 4 | config = require( '../' ), 5 | stylelint = require( 'stylelint' ), 6 | validCss = fs.readFileSync( 7 | './__tests__/vendor-prefixes-valid.css', 8 | 'utf-8' 9 | ); 10 | 11 | describe( 'flags no warnings with valid vendor prefixes css', () => { 12 | let result; 13 | 14 | beforeEach( () => { 15 | result = stylelint.lint( { 16 | code: validCss, 17 | config, 18 | } ); 19 | } ); 20 | 21 | it( 'did not error', () => { 22 | return result.then( ( data ) => expect( data.errored ).toBeFalsy() ); 23 | } ); 24 | 25 | it( 'flags no warnings', () => { 26 | return result.then( ( data ) => 27 | expect( data.results[ 0 ].warnings ).toHaveLength( 0 ) 28 | ); 29 | } ); 30 | } ); 31 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'stylelint-config-recommended', 5 | rules: { 6 | 'at-rule-empty-line-before': [ 7 | 'always', 8 | { 9 | except: [ 'blockless-after-blockless' ], 10 | ignore: [ 'after-comment' ], 11 | }, 12 | ], 13 | 'at-rule-name-case': 'lower', 14 | 'at-rule-name-space-after': 'always-single-line', 15 | 'at-rule-no-unknown': true, 16 | 'at-rule-semicolon-newline-after': 'always', 17 | 'block-closing-brace-newline-after': 'always', 18 | 'block-closing-brace-newline-before': 'always', 19 | 'block-opening-brace-newline-after': 'always', 20 | 'block-opening-brace-space-before': 'always', 21 | 'color-hex-case': 'lower', 22 | 'color-hex-length': 'short', 23 | 'color-named': 'never', 24 | 'comment-empty-line-before': [ 25 | 'always', 26 | { 27 | ignore: [ 'stylelint-commands' ], 28 | }, 29 | ], 30 | 'declaration-bang-space-after': 'never', 31 | 'declaration-bang-space-before': 'always', 32 | 'declaration-block-no-duplicate-properties': [ 33 | true, 34 | { 35 | ignore: [ 'consecutive-duplicates' ], 36 | }, 37 | ], 38 | 'declaration-block-semicolon-newline-after': 'always', 39 | 'declaration-block-semicolon-space-before': 'never', 40 | 'declaration-block-trailing-semicolon': 'always', 41 | 'declaration-colon-newline-after': 'always-multi-line', 42 | 'declaration-colon-space-after': 'always-single-line', 43 | 'declaration-colon-space-before': 'never', 44 | 'declaration-property-unit-allowed-list': { 45 | 'line-height': [ 'px' ], 46 | }, 47 | 'font-family-name-quotes': 'always-where-recommended', 48 | 'font-weight-notation': [ 49 | 'numeric', 50 | { 51 | ignore: [ 'relative' ], 52 | }, 53 | ], 54 | 'function-comma-space-after': 'always', 55 | 'function-comma-space-before': 'never', 56 | 'function-max-empty-lines': 1, 57 | 'function-name-case': [ 58 | 'lower', 59 | { 60 | ignoreFunctions: [ '/^DXImageTransform.Microsoft.*$/' ], 61 | }, 62 | ], 63 | 'function-parentheses-space-inside': 'never', 64 | 'function-url-quotes': 'never', 65 | 'function-whitespace-after': 'always', 66 | indentation: 'tab', 67 | 'length-zero-no-unit': true, 68 | 'max-empty-lines': 2, 69 | 'max-line-length': [ 70 | 80, 71 | { 72 | ignore: 'non-comments', 73 | ignorePattern: [ 74 | '/(https?://[0-9,a-z]*.*)|(^description\\:.+)|(^tags\\:.+)/i', 75 | ], 76 | }, 77 | ], 78 | 'media-feature-colon-space-after': 'always', 79 | 'media-feature-colon-space-before': 'never', 80 | 'media-feature-range-operator-space-after': 'always', 81 | 'media-feature-range-operator-space-before': 'always', 82 | 'media-query-list-comma-newline-after': 'always-multi-line', 83 | 'media-query-list-comma-space-after': 'always-single-line', 84 | 'media-query-list-comma-space-before': 'never', 85 | 'no-eol-whitespace': true, 86 | 'no-missing-end-of-source-newline': true, 87 | 'number-leading-zero': 'always', 88 | 'number-no-trailing-zeros': true, 89 | 'property-case': 'lower', 90 | 'rule-empty-line-before': [ 91 | 'always', 92 | { 93 | ignore: [ 'after-comment' ], 94 | }, 95 | ], 96 | 'selector-attribute-brackets-space-inside': 'never', 97 | 'selector-attribute-operator-space-after': 'never', 98 | 'selector-attribute-operator-space-before': 'never', 99 | 'selector-attribute-quotes': 'always', 100 | 'selector-class-pattern': [ 101 | '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$', 102 | { 103 | message: 104 | 'Selector should use lowercase and separate words with hyphens (selector-class-pattern)', 105 | }, 106 | ], 107 | 'selector-id-pattern': [ 108 | '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$', 109 | { 110 | message: 111 | 'Selector should use lowercase and separate words with hyphens (selector-id-pattern)', 112 | }, 113 | ], 114 | 'selector-combinator-space-after': 'always', 115 | 'selector-combinator-space-before': 'always', 116 | 'selector-list-comma-newline-after': 'always', 117 | 'selector-list-comma-space-before': 'never', 118 | 'selector-max-empty-lines': 0, 119 | 'selector-pseudo-class-case': 'lower', 120 | 'selector-pseudo-class-parentheses-space-inside': 'never', 121 | 'selector-pseudo-element-case': 'lower', 122 | 'selector-pseudo-element-colon-notation': 'double', 123 | 'selector-type-case': 'lower', 124 | 'string-quotes': 'double', 125 | 'unit-case': 'lower', 126 | 'value-keyword-case': 'lower', 127 | 'value-list-comma-newline-after': 'always-multi-line', 128 | 'value-list-comma-space-after': 'always-single-line', 129 | 'value-list-comma-space-before': 'never', 130 | }, 131 | }; 132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-config-wordpress", 3 | "version": "17.0.0", 4 | "description": "WordPress shareable config for stylelint", 5 | "author": "stylelint", 6 | "license": "MIT", 7 | "keywords": [ 8 | "code", 9 | "code style", 10 | "css", 11 | "lint", 12 | "linter", 13 | "linting", 14 | "stylelint", 15 | "stylelint-config", 16 | "stylelint-config-wordpress", 17 | "validate", 18 | "wordpress", 19 | "WordPress" 20 | ], 21 | "homepage": "https://github.com/WordPress-Coding-Standards/stylelint-config-wordpress", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/WordPress-Coding-Standards/stylelint-config-wordpress.git" 25 | }, 26 | "bugs": "https://github.com/WordPress-Coding-Standards/stylelint-config-wordpress/issues", 27 | "engines": { 28 | "node": ">=10" 29 | }, 30 | "files": [ 31 | "CHANGELOG.md", 32 | "LICENSE", 33 | "README.md", 34 | "index.js", 35 | "scss.js" 36 | ], 37 | "main": "index.js", 38 | "dependencies": { 39 | "stylelint-config-recommended": "^3.0.0", 40 | "stylelint-config-recommended-scss": "^4.2.0", 41 | "stylelint-scss": "^3.17.2" 42 | }, 43 | "devDependencies": { 44 | "@commitlint/cli": "^8.3.5", 45 | "@commitlint/config-conventional": "^8.3.4", 46 | "@wordpress/scripts": "^10.0.0", 47 | "husky": "^4.2.3", 48 | "npm-run-all": "^4.1.5", 49 | "npmpub": "^5.0.0", 50 | "remark-cli": "^8.0.0", 51 | "remark-preset-lint-consistent": "^3.0.0", 52 | "remark-preset-lint-recommended": "^4.0.0", 53 | "stylelint": "^13.2.0", 54 | "stylelint-find-rules": "^2.2.0" 55 | }, 56 | "peerDependencies": { 57 | "stylelint": "^10.1.0 || ^11.0.0 || ^12.0.0 || ^13.0.0" 58 | }, 59 | "scripts": { 60 | "check-engines": "wp-scripts check-engines --package", 61 | "check-licenses": "wp-scripts check-licenses --production", 62 | "dry-release": "npmpub --dry --verbose", 63 | "format:js": "wp-scripts format-js", 64 | "lint:css": "wp-scripts lint-style", 65 | "lint:js": "wp-scripts lint-js", 66 | "lint:md": "remark . --quiet --frail", 67 | "lint:pkg-json": "wp-scripts lint-pkg-json", 68 | "lint": "npm-run-all --parallel lint:*", 69 | "pretest": "npm run lint", 70 | "release": "npmpub --verbose", 71 | "stylelint-find-unused-rules": "stylelint-find-rules --config index.js", 72 | "test:unit": "wp-scripts test-unit-js", 73 | "test": "npm run test:unit", 74 | "watch": "jest --watch" 75 | }, 76 | "commitlint": { 77 | "extends": [ 78 | "@commitlint/config-conventional" 79 | ] 80 | }, 81 | "eslintConfig": { 82 | "root": true, 83 | "extends": [ 84 | "plugin:@wordpress/eslint-plugin/recommended" 85 | ], 86 | "rules": { 87 | "linebreak-style": 0 88 | } 89 | }, 90 | "husky": { 91 | "hooks": { 92 | "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" 93 | } 94 | }, 95 | "npmpackagejsonlint": { 96 | "extends": "@wordpress/npm-package-json-lint-config", 97 | "rules": { 98 | "valid-values-license": [ 99 | "error", 100 | [ 101 | "MIT" 102 | ] 103 | ] 104 | } 105 | }, 106 | "remarkConfig": { 107 | "presets": [ 108 | "lint-recommended", 109 | "lint-consistent" 110 | ] 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | useTabs: true, 3 | tabWidth: 4, 4 | printWidth: 80, 5 | singleQuote: true, 6 | trailingComma: 'es5', 7 | bracketSpacing: true, 8 | parenSpacing: true, 9 | jsxBracketSameLine: false, 10 | semi: true, 11 | arrowParens: 'always', 12 | }; 13 | -------------------------------------------------------------------------------- /scss.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: [ './', 'stylelint-config-recommended-scss' ].map( 5 | require.resolve 6 | ), 7 | 8 | plugins: [ 'stylelint-scss' ], 9 | 10 | rules: { 11 | // stylelint-config-wordpress css overrides 12 | 'at-rule-empty-line-before': [ 13 | 'always', 14 | { 15 | except: [ 'blockless-after-blockless' ], 16 | ignore: [ 'after-comment' ], 17 | ignoreAtRules: [ 'else' ], 18 | }, 19 | ], 20 | 21 | 'block-opening-brace-space-before': 'always', 22 | 'block-closing-brace-newline-after': [ 23 | 'always', 24 | { 25 | ignoreAtRules: [ 'if', 'else' ], 26 | }, 27 | ], 28 | 'at-rule-name-space-after': 'always', 29 | 'scss/at-else-closing-brace-newline-after': 'always-last-in-chain', 30 | 'scss/at-else-closing-brace-space-after': 'always-intermediate', 31 | 'scss/at-else-empty-line-before': 'never', 32 | 'scss/at-if-closing-brace-newline-after': 'always-last-in-chain', 33 | 'scss/at-if-closing-brace-space-after': 'always-intermediate', 34 | 'scss/selector-no-redundant-nesting-selector': true, 35 | }, 36 | }; 37 | --------------------------------------------------------------------------------