├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RELEASE.md ├── __tests__ ├── README.md ├── at-rule-disallowed-list.test.mjs ├── at-rule-no-unknown.test.mjs ├── at-rule-no-vendor-prefix.test.mjs ├── block-no-empty.test.mjs ├── block-opening-brace-space-before.test.mjs ├── color-hex-case.test.mjs ├── color-hex-length.test.mjs ├── color-named.test.mjs ├── color-no-invalid-hex.test.mjs ├── declaration-bang-space-after.test.mjs ├── declaration-bang-space-before.test.mjs ├── declaration-block-semicolon-newline-after.test.mjs ├── declaration-block-semicolon-space-before.test.mjs ├── declaration-block-single-line-max-declarations.test.mjs ├── declaration-block-trailing-semicolon.test.mjs ├── declaration-colon-space-after.test.mjs ├── declaration-colon-space-before.test.mjs ├── declaration-property-value-disallowed-list.test.mjs ├── function-comma-space-after.test.mjs ├── function-parentheses-space-inside.test.mjs ├── function-url-quotes.test.mjs ├── indentation.test.mjs ├── length-zero-no-unit.test.mjs ├── max-nesting-depth.test.mjs ├── media-feature-name-no-vendor-prefix.test.mjs ├── media-feature-parentheses-space-inside.test.mjs ├── misc-valid-scss.test.mjs ├── no-missing-end-of-source-newline.test.mjs ├── number-leading-zero.test.mjs ├── number-no-trailing-zeros.test.mjs ├── property-no-unknown.test.mjs ├── property-no-vendor-prefix.test.mjs ├── rule-empty-line-before.test.mjs ├── scss-at-extend-no-missing-placeholder.test.mjs ├── scss-at-function-pattern.test.mjs ├── scss-at-import-partial-extension-disallowed-list.test.mjs ├── scss-at-rule-no-unknown.test.mjs ├── scss-dollar-variable-colon-space-after.test.mjs ├── scss-dollar-variable-colon-space-before.test.mjs ├── scss-dollar-variable-pattern.test.mjs ├── scss-load-no-partial-leading-underscore.test.mjs ├── scss-no-global-function-names.test.mjs ├── scss-percent-placeholder-pattern.mjs ├── scss-selector-no-redundant-nesting-selector.test.mjs ├── selector-class-pattern.test.mjs ├── selector-list-comma-newline-after.test.mjs ├── selector-max-compound-selectors.test.mjs ├── selector-max-id.test.mjs ├── selector-no-qualifying-type.test.mjs ├── selector-no-vendor-prefix.test.mjs ├── selector-pseudo-element-colon-notation.test.mjs ├── selector-pseudo-element-no-unknown.test.mjs ├── shorthand-property-no-redundant-values.test.mjs ├── string-quotes.test.mjs └── value-no-vendor-prefix.test.mjs ├── index.js ├── package-lock.json └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | # Increase the version requirement only when required by the new version. 9 | # More info: https://help.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#versioning-strategy 10 | versioning-strategy: increase-if-necessary 11 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | env: 4 | CI: true 5 | 6 | jobs: 7 | run: 8 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | node: [18, 20, 22] 15 | os: [ubuntu-latest] 16 | 17 | steps: 18 | - name: Clone repository 19 | uses: actions/checkout@v2 20 | 21 | - name: Set Node.js version 22 | uses: actions/setup-node@v1 23 | with: 24 | node-version: ${{ matrix.node }} 25 | 26 | - run: node --version 27 | - run: npm --version 28 | 29 | - name: Install npm dependencies 30 | run: npm ci 31 | 32 | - name: Run tests 33 | run: npm run test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.css.map 2 | .bundle 3 | .sass-cache 4 | node_modules 5 | npm-debug.log 6 | vendor 7 | coverage 8 | .nyc_output 9 | .history -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [12.1.0] 8 | Full list of changes can be [viewed here](https://github.com/bjankord/stylelint-config-sass-guidelines/compare/v12.0.0...v12.1.0) 9 | ### Changed 10 | - Bumped @stylistic/stylelint-plugin from 2.1.2 to 3.0.1 11 | - Bumped stylelint from 16.6.1 to 16.9.0 12 | - Bumped postcss from 8.4.39 to 8.4.45 13 | - Bumped stylelint-scss from 6.4.1 to 6.6.0 14 | 15 | ## [12.0.0] 16 | Full list of changes can be [viewed here](https://github.com/bjankord/stylelint-config-sass-guidelines/compare/v11.1.0...v12.0.0) 17 | ### Added 18 | - Added the following stylistic rules back that were removed in v10 thanks to the [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic/tree/main) 19 | - `@stylistic/block-opening-brace-space-before` 20 | - `@stylistic/color-hex-case` 21 | - `@stylistic/declaration-bang-space-after` 22 | - `@stylistic/declaration-bang-space-before` 23 | - `@stylistic/declaration-block-semicolon-newline-after` 24 | - `@stylistic/declaration-block-semicolon-space-before` 25 | - `@stylistic/declaration-block-trailing-semicolon` 26 | - `@stylistic/declaration-colon-space-after` 27 | - `@stylistic/declaration-colon-space-before` 28 | - `@stylistic/function-comma-space-after` 29 | - `@stylistic/function-parentheses-space-inside` 30 | - `@stylistic/indentation` 31 | - `@stylistic/media-feature-parentheses-space-inside` 32 | - `@stylistic/no-missing-end-of-source-newline` 33 | - `@stylistic/number-leading-zero` 34 | - `@stylistic/number-no-trailing-zeros` 35 | - `@stylistic/selector-list-comma-newline-after` 36 | - `@stylistic/string-quotes` 37 | 38 | ## [11.1.0] 39 | Full list of changes can be [viewed here](https://github.com/bjankord/stylelint-config-sass-guidelines/compare/v11.0.0...v11.1.0) 40 | ### Changed 41 | - Replaced deprecated `scss/at-import-partial-extension-blacklist` with `scss/at-import-partial-extension-disallowed-list` rule. [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/317) 42 | - Modernized unit test to use node:test. [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/318) 43 | - Minor dependency updates 44 | 45 | ## [11.0.0] 46 | ### Changed 47 | - Updated package to be compatible with stylelint v16 48 | - Replaced deprecated `"scss/at-import-no-partial-leading-underscore": true` rule with new `"scss/load-no-partial-leading-underscore": true` rule 49 | 50 | ### Removed 51 | - Removed Node.js less than 18.12.0 support 52 | 53 | ## [10.0.0] 54 | ### Changed 55 | - Updated package to be compatible with stylelint v15 56 | 57 | ### Added 58 | - Added node 18 to automated test matrix 59 | - Added scss/no-global-function-names rule. Resolves [#268](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/268) 60 | 61 | ### Removed 62 | - Dropped official support for Node 12 63 | - Removed node 12 from automated test matrix 64 | - Removed stylelint-order plugin. Resolves [#214](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/214) and [#231](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/231) 65 | - Removed tests for deprecated stylelint rules 66 | - Removed deprecated stylelint rules 67 | - "block-opening-brace-space-before": "always" 68 | - "color-hex-case": "lower" 69 | - "declaration-bang-space-after": "never" 70 | - "declaration-bang-space-before": "always" 71 | - "declaration-block-semicolon-newline-after": "always" 72 | - "declaration-block-semicolon-space-before": "never" 73 | - "declaration-block-trailing-semicolon": "always" 74 | - "declaration-colon-space-after": "always-single-line" 75 | - "declaration-colon-space-before": "never" 76 | - "function-comma-space-after": "always-single-line" 77 | - "function-parentheses-space-inside": "never" 78 | - "indentation": 2 79 | - "media-feature-parentheses-space-inside": "never" 80 | - "no-missing-end-of-source-newline": true 81 | - "number-leading-zero": "always" 82 | - "number-no-trailing-zeros": true 83 | - "selector-list-comma-newline-after": "always" 84 | - "string-quotes": "single" 85 | - Removed scss/at-mixin-pattern rule. Resolves [#181](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/181) and [#191](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/191) 86 | 87 | ## [9.0.1] 88 | ### Changed 89 | - Add postcss ^8.3.3 as a peerDependency. Mitigates https://github.com/bjankord/stylelint-config-sass-guidelines/issues/203 90 | 91 | ## [9.0.0] 92 | ### Changed 93 | - Updated repo to be compatible with stylelint v14. Updated stylelint peerDependency range from `^13.0.0` to `^14.0.0` [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/197) 94 | - Renamed tests files extension from `.js`to `.spec.js` 95 | - Moved manually tested passing and failing SCSS examples into `__tests__/manual-test-cases` 96 | 97 | ### Added 98 | - Added node 16 to automated test matrix 99 | 100 | ### Removed 101 | - Dropped official support for Node 10 [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/197) 102 | - Removed node 10 from automated test matrix [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/198) 103 | - Removed babel as a dev dependency, resolves issue with security vuln in glob-parent CVE-2020-28469 104 | - Removed `src/.stylelint.json` 105 | 106 | ## [8.0.0] 107 | ### Added 108 | - Set node engine minimum to version 10.0.0 109 | - Added node 14 to automated test matrix 110 | 111 | ### Removed 112 | - Dropped official support for Node 8 113 | - Removed node 8 from automated test matrix 114 | 115 | ## [7.1.0] 116 | ### Changed 117 | - Add dependabot integration to help with keeping dependencies up to date and secure 118 | - Bumped up `stylelint` peer/dev dependency to v13.7.0 119 | 120 | ### Fixed 121 | - Replaced deprecated `at-rule-blacklist` rule with `at-rule-disallowed-list` rule 122 | - Replaced deprecated `declaration-property-value-blacklist` rule with `declaration-property-value-disallowed-list` rule 123 | 124 | ### Removed 125 | - Removed unused scss-lint files, these were only used to generate lint errors for comparison with stylelint and did not play a functional role in how this stylelint config worked 126 | - Removed unused Gemfile 127 | - Removed unused Gemfile.lock 128 | - Removed src/.scss-lint.yml 129 | 130 | ## [7.0.0] 131 | ### Changed 132 | - Updated stylelint peerDependency range from `^10.0.1 || ^11.0.0 || ^12.0.0` to `^13.0.0` 133 | 134 | **Node.js v10 or newer** is required. That's because stylelint v13 itself [doesn't support Node.js versions below 10](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md#1300). 135 | 136 | - Bumped up `stylelint-order` dependency to `^4.0.0` 137 | - Update test expectations to not require specific error message order 138 | 139 | ## [7.0.0] 140 | ### Changed 141 | - Updated stylelint peerDependency range from `^10.0.1 || ^11.0.0 || ^12.0.0` to `^13.0.0` 142 | 143 | **Node.js v10 or newer** is required. That's because stylelint v13 itself [doesn't support Node.js versions below 10](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md#1300). 144 | 145 | - Bumped up `stylelint-order` dependency to `^4.0.0` 146 | - Update test expectations to not require specific error message order 147 | 148 | ## [6.2.0] 149 | ### Changed 150 | - Updated stylelint peerDependency range from `^10.0.1 || ^11.0.0` to `^10.0.1 || ^11.0.0 || ^12.0.0` to include stylelint 12 151 | 152 | ## [6.1.0] 153 | ### Changed 154 | - Updated stylelint peerDependency range from `^10.0.1` to `^10.0.1 || ^11.0.0` 155 | 156 | ## [6.0.0] 157 | ### Changed 158 | - Bumped up `stylelint` peer/dev dependency to `^10.0.1` 159 | - Bumped up `stylelint-order` dependency to `^3.0.0` 160 | - Node.js 8.7.0 or greater is now required 161 | 162 | ## [5.4.0] 163 | ### Fixed 164 | - Fix patterns for variables like "$x1". [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/43) 165 | 166 | ### Changed 167 | - Ignore all @-rules in max-nesting-depth. [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/45) 168 | 169 | ## [5.3.0] 170 | ### Changed 171 | - Updated `stylelint-order` dependency range to pull in 1.x or 2.x versions. Both major versions are compatible. [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/41) 172 | - Updated up `stylelint-scss` dependency to pull minimum of 3.4.0 [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/41) 173 | 174 | ## [5.2.0] 175 | ### Changed 176 | - Bumped up `stylelint-order` dependency to ^1.0.0 [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/32) 177 | 178 | ## [5.1.0] 179 | ### Added 180 | - Added ability to run tests on Windows [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/34) 181 | 182 | ### Changed 183 | - Ignore @each for max-nesting-depth [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/35) 184 | 185 | ## [5.0.0] 186 | ### Added 187 | - Added scss/at-rule-no-unknown rule [#18](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/18) 188 | 189 | ### Changed 190 | - Bumped up `stylelint` peer/dev dependency to v9.0.0 191 | - Added stylelint-scss and stylelint-order as dependencies [#22](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/22) 192 | - Node.js 6.x or greater is now required [#24](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/24)) 193 | 194 | ## [4.2.0] 195 | ### Added 196 | - Add "ignore" options to "max-nesting-depth" rule (fixes [#25](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/25)) [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/26) 197 | 198 | ## [4.1.0] 199 | ### Changed 200 | - Bumped up `stylelint-order` to v0.8.0 201 | 202 | ### Fixed 203 | - Fixed border zero rule. Issue [16](https://github.com/bjankord/stylelint-config-sass-guidelines/issues/16) 204 | 205 | ## [4.0.1] 206 | ### Removed 207 | - Removed `{"type": "at-rule", "hasBlock": true }` from order rule. Causes issues with `@media` queries and `@for` loops 208 | - Removed `{"type": "rule", "selector": "/^&:\\w/"},` from order rule. 209 | - Removed `{"type": "rule", "selector": "/^&::\\w/"},` from order rule. 210 | 211 | ## [4.0.0] 212 | ### Added 213 | - Add rules & tests for declaration-order [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/15) 214 | 215 | ### Changed 216 | - Moved stylelint, stylelint-scss, stylelint-order to peerDependencies / devDependencies [PR](https://github.com/bjankord/stylelint-config-sass-guidelines/pull/17/files) 217 | 218 | ## [3.0.1] 219 | ### Changed 220 | - Update copyright years in license 221 | 222 | ## [3.0.0] 223 | ### Added 224 | - Added [greenkeeper](https://greenkeeper.io/) to help keep dependencies up to date 225 | 226 | ### Changed 227 | - Bumped up `stylelint` to v8.0.0 228 | - Bumped up `stylelint-order` to v0.6.0 229 | 230 | ### Removed 231 | - Removed unused `stylelint-selector-no-utility` dependency from package.json 232 | 233 | ## [3.0.0-rc.1] 234 | ### Added 235 | - Added [greenkeeper](https://greenkeeper.io/) to help keep dependencies up to date 236 | 237 | ### Changed 238 | - Bumped up `stylelint` to v8.0.0 239 | - Bumped up `stylelint-order` to v0.6.0 240 | 241 | ### Removed 242 | - Removed unused `stylelint-selector-no-utility` dependency from package.json 243 | 244 | ## [2.2.0] 245 | ### Changed 246 | - Bumped up `stylelint` to v7.12.0 247 | 248 | ### Fixed 249 | - Replaced deprecated `selector-no-id` rule with `selector-max-id` rule 250 | 251 | ## [2.1.0] 252 | ### Changed 253 | - Bumped up `stylelint-order` to v0.4.3 254 | 255 | ### Fixed 256 | - Replaced deprecated `order/declaration-block-properties-alphabetical-order` rule with `order/properties-alphabetical-order` rule 257 | 258 | ## [2.0.0] 259 | ### Added 260 | - Added `stylelint-order` plugin 261 | 262 | ### Changed 263 | - Bumped up `stylelint` to v7.8.0 264 | - Bumped up `stylelint-scss` to v1.4.1 265 | 266 | ### Fixed 267 | - Replaced deprecated `declaration-block-properties-order` rule with `order/declaration-block-properties-alphabetical-order` rule 268 | - Replaced deprecated `rule-nested-empty-line-before` rule with `rule-empty-line-before` rule 269 | - Replaced deprecated `rule-non-nested-empty-line-before` rule with `rule-empty-line-before` rule 270 | 271 | ### Removed 272 | - `stylelint-disable-reason` rule. This rule has been deprecated in stylelint 7.8 and in 8.0 will be removed. See stylelint CHANGELOG: https://stylelint.io/CHANGELOG/#780 273 | 274 | ## [1.1.1] 275 | ### Fixed 276 | - Regex for selector-class-pattern now matches lowercase with hyphens correctly 277 | - Updated test for url-quotes.js to match updated error text 278 | 279 | ## [1.1.0] 280 | ### Added 281 | - `scss/dollar-variable-colon-space-after` rule 282 | - `scss/dollar-variable-colon-space-before` rule 283 | 284 | ### Changed 285 | - Bumped up `stylelint` to v7.1.0 286 | - Bumped up `stylelint-scss` to v1.3.4 287 | 288 | ## [1.0.0] 289 | ### Added 290 | - `stylelint-disable-reason` rule 291 | - `property-no-unknown` rule 292 | - `media-feature-parentheses-space-inside` rule 293 | - `no-missing-end-of-source-newline` rule 294 | 295 | ### Changed 296 | - Bumped up `stylelint` to v7.0.2 297 | - Bumped up `stylelint-scss` to v1.2.1 298 | 299 | ### Removed 300 | - `no-missing-eof-newline `rule 301 | - `function-calc-no-unspaced-operator` rule 302 | 303 | ## [0.2.0] 304 | ### Added 305 | - `function-parentheses-space-inside` rule 306 | - `scss/at-import-partial-extension-blacklist` rule 307 | - `declaration-block-properties-order` rule 308 | - `selector-no-vendor-prefix` rule 309 | - `media-feature-name-no-vendor-prefix` rule 310 | - `at-rule-no-vendor-prefix` rule 311 | 312 | ### Fixed 313 | - Sorted stylelint rules alphabetically in config 314 | - `max-nesting-depth` rule set to 1 to match Sass Guidelines NestingDepth max_depth: 1 rule 315 | - Cleaned up comments in `failing-test-case.scss` 316 | - Declaration order now sorted alphabetically in `passing-test-case.scss` 317 | - Updated tests to account for new rules 318 | 319 | ### Removed 320 | - `block-closing-brace-newline-after` rule 321 | - `no-extra-semicolons` rule 322 | - `string-no-newline` rule 323 | 324 | ## [0.1.0] 325 | ### Added 326 | - Initial release 327 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at osscodeofconduct@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this project 2 | 3 | Please take a moment to review this document in order to make the contribution 4 | process easy and effective for everyone involved. 5 | 6 | Following these guidelines helps to communicate that you respect the time of 7 | the developers managing and developing this open source project. In return, 8 | they should reciprocate that respect in addressing your issue or assessing 9 | patches and features. 10 | 11 | 12 | ## Using the issue tracker 13 | 14 | The issue tracker is the preferred channel for [bug reports](#bugs), 15 | [features requests](#features) and [submitting pull 16 | requests](#pull-requests). 17 | 18 | 19 | 20 | ## Bug reports 21 | 22 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 23 | Good bug reports are extremely helpful - thank you! 24 | 25 | Guidelines for bug reports: 26 | 27 | 1. **Use the GitHub issue search** — check if the issue has already been 28 | reported. 29 | 30 | 2. **Check if the issue has been fixed** — try to reproduce it using the 31 | latest `master` or development branch in the repository. 32 | 33 | 3. **Isolate the problem** — create a [reduced test 34 | case](http://css-tricks.com/reduced-test-cases/) and a live example. 35 | 36 | A good bug report shouldn't leave others needing to chase you up for more 37 | information. Please try to be as detailed as possible in your report. What is 38 | your environment? What steps will reproduce the issue? What browser(s) and OS 39 | experience the problem? What would you expect to be the outcome? All these 40 | details will help people to fix any potential bugs. 41 | 42 | Example: 43 | 44 | > Short and descriptive example bug report title 45 | > 46 | > A summary of the issue and the browser/OS environment in which it occurs. If 47 | > suitable, include the steps required to reproduce the bug. 48 | > 49 | > 1. This is the first step 50 | > 2. This is the second step 51 | > 3. Further steps, etc. 52 | > 53 | > `` - a link to the reduced test case 54 | > 55 | > Any other information you want to share that is relevant to the issue being 56 | > reported. This might include the lines of code that you have identified as 57 | > causing the bug, and potential solutions (and your opinions on their 58 | > merits). 59 | 60 | 61 | 62 | ## Feature requests 63 | 64 | Feature requests are welcome. But take a moment to find out whether your idea 65 | fits with the scope and aims of the project. It's up to *you* to make a strong 66 | case to convince the project's developers of the merits of this feature. Please 67 | provide as much detail and context as possible. 68 | 69 | 70 | 71 | ## Pull requests 72 | 73 | Good pull requests - patches, improvements, new features - are a fantastic 74 | help. They should remain focused in scope and avoid containing unrelated 75 | commits. 76 | 77 | The scope of this project is to provide a stylelint config file with equivealent linting rules to the scss-lint rules recommended by [Sass Guidelines](https://sass-guidelin.es/) 78 | 79 | **Please ask first** before embarking on any significant pull request (e.g. 80 | implementing features, refactoring code, porting to a different language), 81 | otherwise you risk spending a lot of time working on something that the 82 | project's developers might not want to merge into the project. 83 | 84 | Please adhere to the coding conventions used throughout a project (indentation, 85 | accurate comments, etc.) and any other requirements (such as test coverage). 86 | 87 | Follow this process if you'd like your work considered for inclusion in the 88 | project: 89 | 90 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, 91 | and configure the remotes: 92 | 93 | ```bash 94 | # Clone your fork of the repo into the current directory 95 | git clone https://github.com//stylelint-config-sass-guidelines 96 | # Navigate to the newly cloned directory 97 | cd stylelint-config-sass-guidelines 98 | # Assign the original repo to a remote called "upstream" 99 | git remote add upstream https://github.com/bjankord/stylelint-config-sass-guidelines 100 | ``` 101 | 102 | 2. If you cloned a while ago, get the latest changes from upstream: 103 | 104 | ```bash 105 | git checkout 106 | git pull upstream 107 | ``` 108 | 109 | 3. Create a new topic branch (off the main project development branch) to 110 | contain your feature, change, or fix: 111 | 112 | ```bash 113 | git checkout -b 114 | ``` 115 | 116 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 117 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 118 | or your code is unlikely be merged into the main project. Use Git's 119 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 120 | feature to tidy up your commits before making them public. 121 | 122 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 123 | 124 | ```bash 125 | git pull [--rebase] upstream 126 | ``` 127 | 128 | 6. Push your topic branch up to your fork: 129 | 130 | ```bash 131 | git push origin 132 | ``` 133 | 134 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 135 | with a clear title and description. 136 | 137 | **IMPORTANT**: By submitting a patch, you agree to allow the project owner to 138 | license your work under the same license as that used by the project. 139 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-Present Brett Jankord 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stylelint-config-sass-guidelines 2 | 3 | [![NPM version](http://img.shields.io/npm/v/stylelint-config-sass-guidelines.svg)](https://www.npmjs.com/package/stylelint-config-sass-guidelines) 4 | [![Build Status](https://github.com/bjankord/stylelint-config-sass-guidelines/workflows/CI/badge.svg)](https://github.com/bjankord/stylelint-config-sass-guidelines/actions?workflow=CI) 5 | [![Known Vulnerabilities](https://snyk.io/test/github/bjankord/stylelint-config-sass-guidelines/badge.svg)](https://snyk.io//test/github/bjankord/stylelint-config-sass-guidelines) 6 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/bjankord/stylelint-config-sass-guidelines/blob/main/CONTRIBUTING.md) 7 | [![Downloads per month](https://img.shields.io/npm/dm/stylelint-config-sass-guidelines.svg)](https://npmcharts.com/compare/stylelint-config-sass-guidelines) 8 | 9 | > A stylelint config inspired by [sass-guidelin.es](https://sass-guidelin.es/). 10 | 11 | This linter has been designed / tested with SCSS syntax based on the SCSS guidelines documented in https://sass-guidelin.es/. It is intended for use with SCSS syntax, not Sass (tab style) syntax. 12 | 13 | This config: 14 | - includes the [`stylelint-scss` plugin module](https://github.com/stylelint-scss/stylelint-scss) and turns on rules for SCSS specific code 15 | - includes the [`@stylistic/stylelint-plugin` plugin module](https://github.com/stylelint-stylistic/stylelint-stylistic) and turns on rules for stylistic settings 16 | - includes the [`postcss-scss` custom syntax module](https://github.com/postcss/postcss-scss) and configures it 17 | - has a peer dependency on [`stylelint`](https://github.com/stylelint/stylelint) 18 | - You'll need to install this package in your project 19 | - has a peer dependency on [`postcss`](https://github.com/postcss/postcss) 20 | - You'll need to install this package in your project 21 | 22 | ## Installation 23 | 24 | Using NPM 25 | ```console 26 | $ npm i -D stylelint postcss stylelint-config-sass-guidelines 27 | ``` 28 | 29 | Using Yarn 30 | ```console 31 | $ yarn add -D stylelint postcss stylelint-config-sass-guidelines 32 | ``` 33 | 34 | Using PNPM 35 | ```console 36 | $ pnpm add -D stylelint postcss stylelint-config-sass-guidelines 37 | ``` 38 | 39 | ## Usage 40 | 41 | Set your stylelint config to: 42 | 43 | ```json 44 | { 45 | "extends": "stylelint-config-sass-guidelines" 46 | } 47 | ``` 48 | 49 | ### Extending the config 50 | 51 | Simply add a `"rules"` key to your config and add your overrides there. 52 | 53 | For example: 54 | 55 | 56 | ```json 57 | { 58 | "extends": "stylelint-config-sass-guidelines", 59 | "rules": { 60 | "selector-max-compound-selectors": 4, 61 | "value-no-vendor-prefix": false 62 | } 63 | } 64 | ``` 65 | 66 | ## Documentation 67 | 68 | ### Configured lints 69 | 70 | This is a list of the lints turned on in this configuration, and what they do. 71 | 72 | #### At-Rule 73 | 74 | * [`at-rule-disallowed-list`](https://stylelint.io/user-guide/rules/at-rule-disallowed-list/): Specify a list of disallowed at-rules. 75 | * `"debug"` Disallow the use of `@debug`. 76 | * [`at-rule-no-unknown`](https://stylelint.io/user-guide/rules/at-rule-no-unknown/): Disallow unknown at-rules. 77 | * [`at-rule-no-vendor-prefix`](https://stylelint.io/user-guide/rules/at-rule-no-vendor-prefix/): Disallow vendor prefixes for at-rules. 78 | 79 | #### Block 80 | 81 | * [`block-no-empty`](https://stylelint.io/user-guide/rules/block-no-empty/): Disallow empty blocks. 82 | 83 | 84 | #### Color 85 | 86 | * [`color-hex-length`](https://stylelint.io/user-guide/rules/color-hex-length/): Always use short hex notation, where available. 87 | * [`color-named`](https://stylelint.io/user-guide/rules/color-named/): Colors must never be named. 88 | * [`color-no-invalid-hex`](https://stylelint.io/user-guide/rules/color-no-invalid-hex/): Hex values must be valid. 89 | 90 | #### Declaration Block 91 | 92 | * [`declaration-block-single-line-max-declarations`](https://stylelint.io/user-guide/rules/declaration-block-single-line-max-declarations/): There should never be more than `1` declaration per line. 93 | 94 | #### Declaration Property 95 | 96 | * [`declaration-property-value-disallowed-list`](https://stylelint.io/user-guide/rules/declaration-property-value-disallowed-list/): Specify a list of disallowed property and value pairs within declarations. 97 | * `^border`: Disallow the use of the word `none` for borders, use `0` instead. The intent of this rule is to enforce consistency, rather than define which is "better." 98 | 99 | #### Function 100 | 101 | * [`function-url-quotes`](https://stylelint.io/user-guide/rules/function-url-quotes/): URLs must always be quoted. 102 | 103 | #### General 104 | 105 | * [`length-zero-no-unit`](https://stylelint.io/user-guide/rules/length-zero-no-unit/): Disallow units for zero lengths. 106 | * [`max-nesting-depth`](https://stylelint.io/user-guide/rules/max-nesting-depth/): Limit the allowed nesting depth to `1`. _Ignore_: Nested at-rules `@media`, `@supports`, and `@include`. 107 | 108 | 109 | #### Media Feature 110 | 111 | * [`media-feature-name-no-vendor-prefix`](https://stylelint.io/user-guide/rules/media-feature-name-no-vendor-prefix/): Disallow vendor prefixes for media feature names. 112 | 113 | 114 | #### Property 115 | 116 | * [`property-no-unknown`](https://stylelint.io/user-guide/rules/property-no-unknown/): Disallow unknown properties 117 | * [`property-no-vendor-prefix`](https://stylelint.io/user-guide/rules/property-no-vendor-prefix/): Disallow vendor prefixes for properties. 118 | * [`shorthand-property-no-redundant-values`](https://stylelint.io/user-guide/rules/shorthand-property-no-redundant-values/): Disallow redundant values in shorthand properties. 119 | 120 | 121 | #### Rule 122 | 123 | * [`rule-empty-line-before`](https://stylelint.io/user-guide/rules/rule-empty-line-before/): There must always be an empty line before multi-line rules. _Except_: Nested rules that are the first of their parent rule. _Ignore_: Rules that come after a comment. 124 | 125 | #### SCSS 126 | 127 | * [`scss/at-extend-no-missing-placeholder`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/at-extend-no-missing-placeholder/README.md): Disallow at-extends (`@extend`) with missing placeholders. 128 | * [`scss/at-function-pattern`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/at-function-pattern/README.md): SCSS functions must be written in lowercase and match the regex `^[a-z]+([a-z0-9-]+[a-z0-9]+)?$`. 129 | * [`scss/at-import-partial-extension-disallowed-list`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/at-import-partial-extension-disallowed-list/README.md): Specify list of disallowed file extensions for partial names in `@import` commands. 130 | * `.scss`: Disallow the use of the `.scss` file extension in imports. 131 | * [`scss/at-rule-no-unknown`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/at-rule-no-unknown/README.md): SCSS mixins must be written in lowercase and match the regex `^[a-z]+([a-z0-9-]+[a-z0-9]+)?$`. 132 | * [`scss/dollar-variable-colon-space-after`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/dollar-variable-colon-space-after/README.md): Require a single space after the colon in $-variable declarations. 133 | * [`scss/dollar-variable-colon-space-before`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/dollar-variable-colon-space-before/README.md): Disallow whitespace before the colon in $-variable declarations. 134 | * [`scss/dollar-variable-pattern`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/dollar-variable-pattern/README.md): SCSS variables must be written in lowercase and match the regex `^[a-z]+([a-z0-9-]+[a-z0-9]+)?$`. 135 | * [`scss/load-no-partial-leading-underscore`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/load-no-partial-leading-underscore/README.md): Disallow leading underscore in partial names in `@import`. 136 | * [`scss/no-global-function-names`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/no-global-function-names/README.md): Disallows the use of global function names, as these global functions are now located inside built-in Sass modules. 137 | * [`scss/percent-placeholder-pattern`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/percent-placeholder-pattern/README.md): SCSS `%`-placeholders must be written in lowercase and match the regex `^[a-z]+([a-z0-9-]+[a-z0-9]+)?$`. 138 | * [`scss/selector-no-redundant-nesting-selector`](https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/selector-no-redundant-nesting-selector/README.md): Disallow redundant nesting selectors (`&`). 139 | 140 | #### Selector 141 | 142 | * [`selector-class-pattern`](https://stylelint.io/user-guide/rules/selector-class-pattern/): Selectors must be written in lowercase and match the regex `^(?:u|is|has)-[a-z][a-zA-Z0-9]*$|^(?!u|is|has)[a-zA-Z][a-zA-Z0-9]*(?:-[a-z][a-zA-Z0-9]*)?(?:--[a-z][a-zA-Z0-9]*)?$`. 143 | * [`selector-max-compound-selectors`](https://stylelint.io/user-guide/rules/selector-max-compound-selectors/): Limit the number of compound selectors in a selector to `3`. 144 | * [`selector-max-id`](https://stylelint.io/user-guide/rules/selector-max-id/): Disallow id selectors. 145 | * [`selector-no-qualifying-type`](https://stylelint.io/user-guide/rules/selector-no-qualifying-type/): Disallow qualifying a selector by type. 146 | * [`selector-no-vendor-prefix`](https://stylelint.io/user-guide/rules/selector-no-vendor-prefix/): Disallow vendor prefixes for selectors. 147 | * [`selector-pseudo-element-colon-notation`](https://stylelint.io/user-guide/rules/selector-pseudo-element-colon-notation/): Applicable pseudo-elements must always use the double colon notation. 148 | * [`selector-pseudo-element-no-unknown`](https://stylelint.io/user-guide/rules/selector-pseudo-element-no-unknown/): Disallow unknown pseudo-element selectors. 149 | 150 | #### Stylistic 151 | * [`@stylistic/block-opening-brace-space-before`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/block-opening-brace-space-before/README.md): There must always be a single space before the opening brace. 152 | * [`@stylistic/color-hex-case`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/color-hex-case/README.md): Hex colors must be written in lowercase. 153 | * [`@stylistic/declaration-bang-space-after`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-bang-space-after/README.md): There must never be whitespace after the bang. 154 | * [`@stylistic/declaration-bang-space-before`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-bang-space-before/README.md): There must always be a single space before the bang. 155 | * [`@stylistic/declaration-block-semicolon-newline-after`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-block-semicolon-newline-after/README.md): There must always be a newline after the semicolon. 156 | * [`@stylistic/declaration-block-semicolon-space-before`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-block-semicolon-space-before/README.md): There must never be whitespace before the semicolons. 157 | * [`@stylistic/declaration-block-trailing-semicolon`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-block-trailing-semicolon/README.md): There must always be a trailing semicolon. 158 | * [`@stylistic/declaration-colon-space-after`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-colon-space-after/README.md): There must always be a single space after the colon if the declaration's value is single-line. 159 | * [`@stylistic/declaration-colon-space-before`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/declaration-colon-space-before/README.md): There must never be whitespace before the colon. 160 | * [`@stylistic/function-comma-space-after`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/function-comma-space-after/README.md): There must always be a single space after the commas in single-line functions. 161 | * [`@stylistic/function-parentheses-space-inside`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/function-parentheses-space-inside/README.md): There must never be whitespace on the inside of the parentheses of functions. 162 | * [`@stylistic/indentation`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/indentation/README.md): Indentation should always be 2 spaces. 163 | 164 | * [`@stylistic/media-feature-parentheses-space-inside`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/media-feature-parentheses-space-inside/README.md): There must never be whitespace on the inside of the parentheses of media features. 165 | * [`@stylistic/no-missing-end-of-source-newline`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/no-missing-end-of-source-newline/README.md): Disallow missing end-of-file newlines in non-empty files. 166 | * [`@stylistic/number-leading-zero`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/number-leading-zero/README.md): There must always be a leading zero. 167 | * [`@stylistic/number-no-trailing-zeros`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/number-no-trailing-zeros/README.md): Disallow trailing zeros in numbers. 168 | * [`@stylistic/selector-list-comma-newline-after`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/selector-list-comma-newline-after/README.md): There must always be a newline after the commas of selector lists. 169 | * [`@stylistic/string-quotes`](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/lib/rules/string-quotes/README.md): Strings must always be wrapped with single quotes. 170 | 171 | #### Value 172 | 173 | * [`value-no-vendor-prefix`](https://stylelint.io/user-guide/rules/value-no-vendor-prefix/): Disallow vendor prefixes for values. 174 | 175 | ## [Changelog](CHANGELOG.md) 176 | 177 | ## Contributors 178 | stylelint-config-sass-guidelines is maintained by Brett Jankord and contributions from the community. Without the code contributions from [all these fantastic people](https://github.com/bjankord/stylelint-config-sass-guidelines/graphs/contributors), stylelint-config-sass-guidelines would not exist. 179 | 180 | ## [License](LICENSE) 181 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # How to release 2 | 3 | This project is hosted on NPM. You can see it [here][npm-url]. 4 | 5 | Releasing the project requires these steps: 6 | 7 | * Decide if you are releasing a major, minor, or patch version 8 | * Do not modify the version number in package.json or create a GitHub release. 9 | * Use the [release scripts][release-scripts-url] to create a new major, minor, or patch release. 10 | * This will update the version in package.json. 11 | * This will also create a git tag for the release. 12 | * Navigate to the GitHub [project release][github-release-url] page and add the version number to release 13 | * Add the CHANGELOG notes to the associated release. 14 | 15 | 16 | 17 | [npm-url]: https://www.npmjs.com/package/stylelint-config-sass-guidelines 18 | [release-scripts-url]: https://github.com/bjankord/stylelint-config-sass-guidelines/blob/main/package.json#L48-L50 19 | [github-release-url]: https://github.com/bjankord/stylelint-config-sass-guidelines/releases 20 | -------------------------------------------------------------------------------- /__tests__/README.md: -------------------------------------------------------------------------------- 1 | # How to add tests 2 | 3 | * Create your test file named after stylelint rule. 4 | * For example, `__tests___/color-hex-case.test.mjs` 5 | * Copy the code from one of the other tests into your test new file 6 | * Update the test so you have code that will produce lint you want to test for 7 | * Write test assertions 8 | -------------------------------------------------------------------------------- /__tests__/at-rule-disallowed-list.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with at-rule-disallowed lint', () => { 9 | const invalidScss = ( 10 | `$color-blue: #1c94c6; 11 | 12 | .test-selector { 13 | @debug $color-blue; 14 | } 15 | `); 16 | 17 | let result; 18 | 19 | beforeEach(async () => { 20 | result = await stylelint.lint({ 21 | code: invalidScss, 22 | config, 23 | }); 24 | }); 25 | 26 | it('did error', () => { 27 | assert.equal(result.errored, true); 28 | }); 29 | 30 | it('flags warnings', () => { 31 | assert.equal(result.results[0].warnings.length, 1); 32 | }); 33 | 34 | it('correct warning text', () => { 35 | assert.deepEqual( 36 | result.results[0].warnings.map((w) => w.text), 37 | [ 38 | 'Unexpected at-rule "@debug" (at-rule-disallowed-list)' 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | 'at-rule-disallowed-list', 48 | ], 49 | ); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /__tests__/at-rule-no-unknown.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with at-rule-no-unknown lint', () => { 9 | const invalidScss = ( 10 | `@unknown { color: #fff; } 11 | 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 1); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected unknown at-rule "@unknown" (scss/at-rule-no-unknown)', 36 | ], 37 | ); 38 | }); 39 | 40 | it('correct rule flagged', () => { 41 | assert.deepEqual( 42 | result.results[0].warnings.map((w) => w.rule), 43 | [ 44 | 'scss/at-rule-no-unknown', 45 | ], 46 | ); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /__tests__/at-rule-no-vendor-prefix.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with at-rule-no-vendor-prefix lint', () => { 9 | const invalidScss = ( 10 | `@-webkit-keyframes anim { 11 | 0% { 12 | opacity: 0; 13 | } 14 | } 15 | `); 16 | 17 | let result; 18 | 19 | beforeEach(async () => { 20 | result = await stylelint.lint({ 21 | code: invalidScss, 22 | config, 23 | }); 24 | }); 25 | 26 | it('did error', () => { 27 | assert.equal(result.errored, true); 28 | }); 29 | 30 | it('flags warnings', () => { 31 | assert.equal(result.results[0].warnings.length, 1); 32 | }); 33 | 34 | it('correct warning text', () => { 35 | assert.deepEqual( 36 | result.results[0].warnings.map((w) => w.text), 37 | [ 38 | 'Unexpected vendor-prefixed at-rule "@-webkit-keyframes" (at-rule-no-vendor-prefix)', 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | 'at-rule-no-vendor-prefix', 48 | ], 49 | ); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /__tests__/block-no-empty.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with block-no-empty lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | } 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 1); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected empty block (block-no-empty)', 36 | ], 37 | ); 38 | }); 39 | 40 | it('correct rule flagged', () => { 41 | assert.deepEqual( 42 | result.results[0].warnings.map((w) => w.rule), 43 | [ 44 | 'block-no-empty', 45 | ], 46 | ); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /__tests__/block-opening-brace-space-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with block-opening-brace-space-before lint', () => { 9 | const invalidScss = ( 10 | `.test-selector{ color: #fff; } 11 | 12 | .test-selector 13 | { color: #fff; } 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 2); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Expected single space before "{" (@stylistic/block-opening-brace-space-before)', 38 | 'Expected single space before "{" (@stylistic/block-opening-brace-space-before)', 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | '@stylistic/block-opening-brace-space-before', 48 | '@stylistic/block-opening-brace-space-before', 49 | ], 50 | ); 51 | }); 52 | }); 53 | 54 | describe('does not flag warnings with valid block-opening-brace-space-before', () => { 55 | const validScss = ( 56 | `.test-selector { 57 | color: #fff; 58 | } 59 | `); 60 | 61 | let result; 62 | 63 | beforeEach(async () => { 64 | result = await stylelint.lint({ 65 | code: validScss, 66 | config, 67 | }); 68 | }); 69 | 70 | it('did not error', () => { 71 | assert.equal(result.errored, false); 72 | }); 73 | 74 | it('does not flag warnings', () => { 75 | assert.equal(result.results[0].warnings.length, 0); 76 | }); 77 | }); -------------------------------------------------------------------------------- /__tests__/color-hex-case.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with color-hex-case lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | color: #FFF; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected "#FFF" to be "#fff" (@stylistic/color-hex-case)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/color-hex-case', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid color-hex-case', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | color: #fff; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/color-hex-length.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with color-hex-length lint', () => { 9 | const invalidScss = ( 10 | `.hexlength { 11 | color: #ff22ee; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected "#ff22ee" to be "#f2e" (color-hex-length)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'color-hex-length', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid color-hex-length', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | color: #fff; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/color-named.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with color-named lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | color: green; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected named color "green" (color-named)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'color-named', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/color-no-invalid-hex.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with color-no-invalid-hex lint', () => { 9 | const invalidScss = ( 10 | `.hex-validation { 11 | background: #ab; // Clearly a typo 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected invalid hex color "#ab" (color-no-invalid-hex)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'color-no-invalid-hex', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/declaration-bang-space-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-bang-space-after lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { color: #fff ! important; } 11 | .test-selector { color: #fff! important; } 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 3); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected whitespace after "!" (@stylistic/declaration-bang-space-after)', 36 | 'Unexpected whitespace after "!" (@stylistic/declaration-bang-space-after)', 37 | 'Expected single space before "!" (@stylistic/declaration-bang-space-before)' 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | '@stylistic/declaration-bang-space-after', 47 | '@stylistic/declaration-bang-space-after', 48 | '@stylistic/declaration-bang-space-before', 49 | ], 50 | ); 51 | }); 52 | }); 53 | 54 | describe('does not flag warnings with valid declaration-bang-space-after', () => { 55 | const validScss = ( 56 | `.test-selector { 57 | color: #000 !important; 58 | } 59 | `); 60 | 61 | let result; 62 | 63 | beforeEach(async () => { 64 | result = await stylelint.lint({ 65 | code: validScss, 66 | config, 67 | }); 68 | }); 69 | 70 | it('did not error', () => { 71 | assert.equal(result.errored, false); 72 | }); 73 | 74 | it('does not flag warnings', () => { 75 | assert.equal(result.results[0].warnings.length, 0); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /__tests__/declaration-bang-space-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-bang-space-before lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { color: #fff!important; } 11 | .test-selector { color: #fff !important; } 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 2); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Expected single space before "!" (@stylistic/declaration-bang-space-before)', 36 | 'Expected single space before "!" (@stylistic/declaration-bang-space-before)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/declaration-bang-space-before', 46 | '@stylistic/declaration-bang-space-before', 47 | ], 48 | ); 49 | }); 50 | }); 51 | 52 | describe('does not flag warnings with valid declaration-bang-space-before', () => { 53 | const validScss = ( 54 | `.test-selector { 55 | color: #000 !important; 56 | } 57 | `); 58 | 59 | let result; 60 | 61 | beforeEach(async () => { 62 | result = await stylelint.lint({ 63 | code: validScss, 64 | config, 65 | }); 66 | }); 67 | 68 | it('did not error', () => { 69 | assert.equal(result.errored, false); 70 | }); 71 | 72 | it('does not flag warnings', () => { 73 | assert.equal(result.results[0].warnings.length, 0); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /__tests__/declaration-block-semicolon-newline-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-block-semicolon-newline-after lint', () => { 9 | const invalidScss = (`.test-selector { color: #fff; top: 0; }`); 10 | 11 | let result; 12 | 13 | beforeEach(async () => { 14 | result = await stylelint.lint({ 15 | code: invalidScss, 16 | config, 17 | }); 18 | }); 19 | 20 | it('did error', () => { 21 | assert.equal(result.errored, true); 22 | }); 23 | 24 | it('flags warnings', () => { 25 | assert.equal(result.results[0].warnings.length, 3); 26 | }); 27 | 28 | it('correct warning text', () => { 29 | assert.deepEqual( 30 | result.results[0].warnings.map((w) => w.text), 31 | [ 32 | 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', 33 | 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)', 34 | 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' 35 | ], 36 | ); 37 | }); 38 | 39 | it('correct rule flagged', () => { 40 | assert.deepEqual( 41 | result.results[0].warnings.map((w) => w.rule), 42 | [ 43 | '@stylistic/declaration-block-semicolon-newline-after', 44 | '@stylistic/no-missing-end-of-source-newline', 45 | 'declaration-block-single-line-max-declarations' 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid declaration-block-semicolon-newline-after', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | color: #fff; 55 | border: 0; 56 | } 57 | 58 | `); 59 | 60 | let result; 61 | 62 | beforeEach(async () => { 63 | result = await stylelint.lint({ 64 | code: validScss, 65 | config, 66 | }); 67 | }); 68 | 69 | it('did not error', () => { 70 | assert.equal(result.errored, false); 71 | }); 72 | 73 | it('does not flag warnings', () => { 74 | assert.equal(result.results[0].warnings.length, 0); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /__tests__/declaration-block-semicolon-space-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-block-semicolon-space-before lint', () => { 9 | const invalidScss = (`.test-selector { color: #fff ; }`); 10 | 11 | let result; 12 | 13 | beforeEach(async () => { 14 | result = await stylelint.lint({ 15 | code: invalidScss, 16 | config, 17 | }); 18 | }); 19 | 20 | it('did error', () => { 21 | assert.equal(result.errored, true); 22 | }); 23 | 24 | it('flags warnings', () => { 25 | assert.equal(result.results[0].warnings.length, 2); 26 | }); 27 | 28 | it('correct warning text', () => { 29 | assert.deepEqual( 30 | result.results[0].warnings.map((w) => w.text), 31 | [ 32 | 'Unexpected whitespace before ";" (@stylistic/declaration-block-semicolon-space-before)', 33 | 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)' 34 | ], 35 | ); 36 | }); 37 | 38 | it('correct rule flagged', () => { 39 | assert.deepEqual( 40 | result.results[0].warnings.map((w) => w.rule), 41 | [ 42 | '@stylistic/declaration-block-semicolon-space-before', 43 | '@stylistic/no-missing-end-of-source-newline' 44 | ], 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/declaration-block-single-line-max-declarations.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-block-single-line-max-declarations lint', () => { 9 | const invalidScss = (` 10 | .test-selector { color: #fff; top: 0; } 11 | 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 2); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', 36 | 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/declaration-block-semicolon-newline-after', 46 | 'declaration-block-single-line-max-declarations' 47 | ], 48 | ); 49 | }); 50 | }); 51 | 52 | describe('does not flag warnings with valid declaration-block-single-line-max-declarations', () => { 53 | const validScss = ( 54 | `.test-selector { color: #000; } 55 | `); 56 | 57 | let result; 58 | 59 | beforeEach(async () => { 60 | result = await stylelint.lint({ 61 | code: validScss, 62 | config, 63 | }); 64 | }); 65 | 66 | it('did not error', () => { 67 | assert.equal(result.errored, false); 68 | }); 69 | 70 | it('does not flag warnings', () => { 71 | assert.equal(result.results[0].warnings.length, 0); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /__tests__/declaration-block-trailing-semicolon.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-block-trailing-semicolon lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { color: #fff } 11 | .test-selector { background: #000; color: #fff } 12 | .test-selector { @include foo } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 5); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', 37 | 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', 38 | 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', 39 | 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', 40 | 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' 41 | ], 42 | ); 43 | }); 44 | 45 | it('correct rule flagged', () => { 46 | assert.deepEqual( 47 | result.results[0].warnings.map((w) => w.rule), 48 | [ 49 | '@stylistic/declaration-block-semicolon-newline-after', 50 | '@stylistic/declaration-block-trailing-semicolon', 51 | '@stylistic/declaration-block-trailing-semicolon', 52 | '@stylistic/declaration-block-trailing-semicolon', 53 | 'declaration-block-single-line-max-declarations' 54 | ], 55 | ); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /__tests__/declaration-colon-space-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-colon-space-after lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | box-shadow:0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, 0.8); 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected single space after ":" with a single-line declaration (@stylistic/declaration-colon-space-after)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/declaration-colon-space-after', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid declaration-colon-space-after', () => { 52 | const validScss = ( 53 | `.test-selector { color: #fff; } 54 | `); 55 | 56 | let result; 57 | 58 | beforeEach(async () => { 59 | result = await stylelint.lint({ 60 | code: validScss, 61 | config, 62 | }); 63 | }); 64 | 65 | it('did not error', () => { 66 | assert.equal(result.errored, false); 67 | }); 68 | 69 | it('does not flag warnings', () => { 70 | assert.equal(result.results[0].warnings.length, 0); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /__tests__/declaration-colon-space-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-colon-space-before lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | color : #fff; 12 | } 13 | 14 | .test-selector { 15 | color :#fff; 16 | } 17 | `); 18 | 19 | let result; 20 | 21 | beforeEach(async () => { 22 | result = await stylelint.lint({ 23 | code: invalidScss, 24 | config, 25 | }); 26 | }); 27 | 28 | it('did error', () => { 29 | assert.equal(result.errored, true); 30 | }); 31 | 32 | it('flags warnings', () => { 33 | assert.equal(result.results[0].warnings.length, 3); 34 | }); 35 | 36 | it('correct warning text', () => { 37 | assert.deepEqual( 38 | result.results[0].warnings.map((w) => w.text), 39 | [ 40 | 'Expected single space after ":" with a single-line declaration (@stylistic/declaration-colon-space-after)', 41 | 'Unexpected whitespace before ":" (@stylistic/declaration-colon-space-before)', 42 | 'Unexpected whitespace before ":" (@stylistic/declaration-colon-space-before)' 43 | ], 44 | ); 45 | }); 46 | 47 | it('correct rule flagged', () => { 48 | assert.deepEqual( 49 | result.results[0].warnings.map((w) => w.rule), 50 | [ 51 | '@stylistic/declaration-colon-space-after', 52 | '@stylistic/declaration-colon-space-before', 53 | '@stylistic/declaration-colon-space-before' 54 | ], 55 | ); 56 | }); 57 | }); 58 | 59 | describe('does not flag warnings with valid declaration-colon-space-before', () => { 60 | const validScss = ( 61 | `.test-selector { color: #fff; } 62 | `); 63 | 64 | let result; 65 | 66 | beforeEach(async () => { 67 | result = await stylelint.lint({ 68 | code: validScss, 69 | config, 70 | }); 71 | }); 72 | 73 | it('did not error', () => { 74 | assert.equal(result.errored, false); 75 | }); 76 | 77 | it('does not flag warnings', () => { 78 | assert.equal(result.results[0].warnings.length, 0); 79 | }); 80 | }); -------------------------------------------------------------------------------- /__tests__/declaration-property-value-disallowed-list.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with declaration-property-value-disallowed-list border none lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | border: none; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected value "none" for property "border" (declaration-property-value-disallowed-list)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'declaration-property-value-disallowed-list', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/function-comma-space-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with function-comma-space-after lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { transform: translate(1,1); } 11 | .test-selector { transform: translate(1 ,1); } 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 2); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Expected single space after "," in a single-line function (@stylistic/function-comma-space-after)', 36 | 'Expected single space after "," in a single-line function (@stylistic/function-comma-space-after)' 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/function-comma-space-after', 46 | '@stylistic/function-comma-space-after' 47 | ], 48 | ); 49 | }); 50 | }); 51 | 52 | describe('does not flag warnings with valid function-comma-space-after', () => { 53 | const validScss = ( 54 | `.test-selector { 55 | @include box-shadow(0 2px 2px rgba(0, 0, 0, 0.2)); 56 | color: rgba(0, 0, 0, 0.1); 57 | } 58 | `); 59 | 60 | let result; 61 | 62 | beforeEach(async () => { 63 | result = await stylelint.lint({ 64 | code: validScss, 65 | config, 66 | }); 67 | }); 68 | 69 | it('did not error', () => { 70 | assert.equal(result.errored, false); 71 | }); 72 | 73 | it('does not flag warnings', () => { 74 | assert.equal(result.results[0].warnings.length, 0); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /__tests__/function-parentheses-space-inside.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with function-parentheses-space-inside lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { transform: translate( 1, 1 ); } 11 | .test-selector { transform: translate(1, 1 ); } 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 3); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected whitespace after "(" (@stylistic/function-parentheses-space-inside)', 36 | 'Unexpected whitespace before ")" (@stylistic/function-parentheses-space-inside)', 37 | 'Unexpected whitespace before ")" (@stylistic/function-parentheses-space-inside)' 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | '@stylistic/function-parentheses-space-inside', 47 | '@stylistic/function-parentheses-space-inside', 48 | '@stylistic/function-parentheses-space-inside' 49 | ], 50 | ); 51 | }); 52 | }); 53 | 54 | describe('does not flag warnings with valid function-parentheses-space-inside', () => { 55 | const validScss = ( 56 | `.test-selector { 57 | @include box-shadow(0 2px 2px rgba(0, 0, 0, 0.2)); 58 | color: rgba(0, 0, 0, 0.1); 59 | } 60 | `); 61 | 62 | let result; 63 | 64 | beforeEach(async () => { 65 | result = await stylelint.lint({ 66 | code: validScss, 67 | config, 68 | }); 69 | }); 70 | 71 | it('did not error', () => { 72 | assert.equal(result.errored, false); 73 | }); 74 | 75 | it('does not flag warnings', () => { 76 | assert.equal(result.results[0].warnings.length, 0); 77 | }); 78 | }); -------------------------------------------------------------------------------- /__tests__/function-url-quotes.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with function-url-quotes lint', () => { 9 | const invalidScss = ( 10 | `.quotes-url { 11 | background: url(example.png); 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected quotes around "url" function argument (function-url-quotes)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'function-url-quotes', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid function-url-quotes', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | background: url('example.png'); 55 | } 56 | 57 | `); 58 | 59 | let result; 60 | 61 | beforeEach(async () => { 62 | result = await stylelint.lint({ 63 | code: validScss, 64 | config, 65 | }); 66 | }); 67 | 68 | it('did not error', () => { 69 | assert.equal(result.errored, false); 70 | }); 71 | 72 | it('does not flag warnings', () => { 73 | assert.equal(result.results[0].warnings.length, 0); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /__tests__/indentation.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with indentation lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | color: #fff; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected indentation of 2 spaces (@stylistic/indentation)' 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/indentation', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid indentation', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | color: #000; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/length-zero-no-unit.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with length-zero-no-unit lint', () => { 9 | const invalidScss = ( 10 | `.zerounit { 11 | margin: 0px; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected unit (length-zero-no-unit)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'length-zero-no-unit', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid length-zero-no-unit', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | margin: 0; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/max-nesting-depth.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with max-nesting-depth lint', () => { 9 | const invalidScss = ( 10 | `.one { 11 | .two { 12 | background-color: #c0ffee; 13 | 14 | @media (min-width: 420px) { 15 | background-color: #bada55; 16 | } 17 | 18 | @include mixin() { 19 | background-color: #ba2; 20 | } 21 | 22 | .three { 23 | color: #f00; 24 | } 25 | } 26 | } 27 | `); 28 | 29 | let result; 30 | 31 | beforeEach(async () => { 32 | result = await stylelint.lint({ 33 | code: invalidScss, 34 | config, 35 | }); 36 | }); 37 | 38 | it('did error', () => { 39 | assert.equal(result.errored, true); 40 | }); 41 | 42 | it('flags warnings', () => { 43 | assert.equal(result.results[0].warnings.length, 1); 44 | }); 45 | 46 | it('correct warning text', () => { 47 | assert.deepEqual( 48 | result.results[0].warnings.map((w) => w.text), 49 | [ 50 | 'Expected nesting depth to be no more than 1 (max-nesting-depth)', 51 | ], 52 | ); 53 | }); 54 | 55 | it('correct rule flagged', () => { 56 | assert.deepEqual( 57 | result.results[0].warnings.map((w) => w.rule), 58 | [ 59 | 'max-nesting-depth' 60 | ], 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /__tests__/media-feature-name-no-vendor-prefix.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with media-feature-name-no-vendor-prefix lint', () => { 9 | const invalidScss = (`@media (-webkit-min-device-pixel-ratio: 1) { 10 | .test-selector { 11 | color: #fff; 12 | } 13 | } 14 | 15 | `); 16 | 17 | let result; 18 | 19 | beforeEach(async () => { 20 | result = await stylelint.lint({ 21 | code: invalidScss, 22 | config, 23 | }); 24 | }); 25 | 26 | it('did error', () => { 27 | assert.equal(result.errored, true); 28 | }); 29 | 30 | it('flags warnings', () => { 31 | assert.equal(result.results[0].warnings.length, 1); 32 | }); 33 | 34 | it('correct warning text', () => { 35 | assert.deepEqual( 36 | result.results[0].warnings.map((w) => w.text), 37 | [ 38 | 'Unexpected vendor-prefix (media-feature-name-no-vendor-prefix)' 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | 'media-feature-name-no-vendor-prefix' 48 | ], 49 | ); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /__tests__/media-feature-parentheses-space-inside.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with media-feature-parentheses-space-inside lint', () => { 9 | const invalidScss = (`@media ( max-width: 300px ) { 10 | .test-selector { 11 | color: #fff; 12 | } 13 | } 14 | 15 | `); 16 | 17 | let result; 18 | 19 | beforeEach(async () => { 20 | result = await stylelint.lint({ 21 | code: invalidScss, 22 | config, 23 | }); 24 | }); 25 | 26 | it('did error', () => { 27 | assert.equal(result.errored, true); 28 | }); 29 | 30 | it('flags warnings', () => { 31 | assert.equal(result.results[0].warnings.length, 2); 32 | }); 33 | 34 | it('correct warning text', () => { 35 | assert.deepEqual( 36 | result.results[0].warnings.map((w) => w.text), 37 | [ 38 | 'Unexpected whitespace after "(" (@stylistic/media-feature-parentheses-space-inside)', 39 | 'Unexpected whitespace before ")" (@stylistic/media-feature-parentheses-space-inside)' 40 | ], 41 | ); 42 | }); 43 | 44 | it('correct rule flagged', () => { 45 | assert.deepEqual( 46 | result.results[0].warnings.map((w) => w.rule), 47 | [ 48 | '@stylistic/media-feature-parentheses-space-inside', 49 | '@stylistic/media-feature-parentheses-space-inside' 50 | ], 51 | ); 52 | }); 53 | }); 54 | 55 | describe('does not flag warnings with valid media-feature-parentheses-space-inside', () => { 56 | const validScss = ( 57 | `@media (max-width: 300px) { 58 | .media-parens { 59 | margin: 0; 60 | } 61 | } 62 | `); 63 | 64 | let result; 65 | 66 | beforeEach(async () => { 67 | result = await stylelint.lint({ 68 | code: validScss, 69 | config, 70 | }); 71 | }); 72 | 73 | it('did not error', () => { 74 | assert.equal(result.errored, false); 75 | }); 76 | 77 | it('does not flag warnings', () => { 78 | assert.equal(result.results[0].warnings.length, 0); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /__tests__/misc-valid-scss.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('does not error or warn on valid scss', () => { 9 | const invalidScss = ( 10 | `// DeclarationOrder test 11 | // scss-lint:disable NestingDepth 12 | .declarationorder { 13 | @extend %error; 14 | @include message-box(); 15 | 16 | color: #f00; 17 | 18 | p { 19 | color: #f00; 20 | } 21 | } 22 | // scss-lint:enable NestingDepth 23 | 24 | // ElsePlacement test 25 | $width: auto; 26 | 27 | .elseplacement { 28 | @if $width == 'auto' { 29 | width: $width; 30 | } @else { 31 | display: inline-block; 32 | width: $width; 33 | } 34 | } 35 | 36 | // EmptyLineBetweenBlocks test 37 | // scss-lint:disable NestingDepth 38 | p { 39 | margin: 0; 40 | 41 | em { 42 | color: #f00; 43 | } 44 | } 45 | 46 | a { 47 | color: #f00; 48 | } 49 | // scss-lint:enable NestingDepth 50 | 51 | 52 | // NameFormat Mixins test 53 | // Mixins should be declared with all lowercase letters and hyphens instead of underscores. 54 | 55 | @mixin my-mixin() { 56 | color: #fff; 57 | } 58 | 59 | // Private Naming Convention test 60 | // Enforces that functions, mixins, and variables that follow the private naming convention (default to underscore-prefixed, e.g. $_foo) are defined and used within the same file. 61 | 62 | $_foo: #f00; 63 | 64 | figure { 65 | color: $_foo; 66 | } 67 | 68 | // SpaceAroundOperator test 69 | .spacearoundoperator { 70 | margin: 5px + 10px; 71 | padding: 5px + 10px; 72 | } 73 | 74 | // Each loop test 75 | .button { 76 | @each $key, $value in $colors { 77 | &-#{$key} { 78 | background-color: $value; 79 | } 80 | } 81 | } 82 | `); 83 | 84 | let result; 85 | 86 | beforeEach(async () => { 87 | result = await stylelint.lint({ 88 | code: invalidScss, 89 | config, 90 | }); 91 | }); 92 | 93 | it('did not error', () => { 94 | // console.log('result.results[0].warnings', result.results[0].warnings); 95 | assert.equal(result.errored, false); 96 | }); 97 | 98 | it('flags no warnings', () => { 99 | assert.equal(result.results[0].warnings.length, 0); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /__tests__/no-missing-end-of-source-newline.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with no-missing-end-of-source-newline lint', () => { 9 | const invalidScss = (`.test-selector { color: #fff; }`); 10 | 11 | let result; 12 | 13 | beforeEach(async () => { 14 | result = await stylelint.lint({ 15 | code: invalidScss, 16 | config, 17 | }); 18 | }); 19 | 20 | it('did error', () => { 21 | assert.equal(result.errored, true); 22 | }); 23 | 24 | it('flags warnings', () => { 25 | assert.equal(result.results[0].warnings.length, 1); 26 | }); 27 | 28 | it('correct warning text', () => { 29 | assert.deepEqual( 30 | result.results[0].warnings.map((w) => w.text), 31 | [ 32 | 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)', 33 | ], 34 | ); 35 | }); 36 | 37 | it('correct rule flagged', () => { 38 | assert.deepEqual( 39 | result.results[0].warnings.map((w) => w.rule), 40 | [ 41 | '@stylistic/no-missing-end-of-source-newline', 42 | ], 43 | ); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /__tests__/number-leading-zero.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with number-leading-zero lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | line-height: .5em; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected a leading zero (@stylistic/number-leading-zero)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/number-leading-zero', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid number-leading-zero', () => { 52 | const validScss = ( 53 | `.test-selector { 54 | line-height: 0.5em; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/number-no-trailing-zeros.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with number-no-trailing-zeros lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | top: 1.0px; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected trailing zero(s) (@stylistic/number-no-trailing-zeros)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | '@stylistic/number-no-trailing-zeros', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | 52 | describe('does not flag warnings with valid number-no-trailing-zeros', () => { 53 | const validScss = ( 54 | `.test-selector { 55 | top: 1px; 56 | } 57 | `); 58 | 59 | let result; 60 | 61 | beforeEach(async () => { 62 | result = await stylelint.lint({ 63 | code: validScss, 64 | config, 65 | }); 66 | }); 67 | 68 | it('did not error', () => { 69 | assert.equal(result.errored, false); 70 | }); 71 | 72 | it('does not flag warnings', () => { 73 | assert.equal(result.results[0].warnings.length, 0); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /__tests__/property-no-unknown.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with property-no-unknown lint', () => { 9 | const invalidScss = ( 10 | `.property-spelling { 11 | diplay: none; // "display" is spelled incorrectly 12 | heigth: 100%; // "height" is spelled incorrectly 13 | } 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 2); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected unknown property "diplay" (property-no-unknown)', 38 | 'Unexpected unknown property "heigth" (property-no-unknown)' 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | 'property-no-unknown', 48 | 'property-no-unknown', 49 | ], 50 | ); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /__tests__/property-no-vendor-prefix.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with property-no-vendor-prefix lint', () => { 9 | const invalidScss = ( 10 | `.test-selector { 11 | -webkit-transform: scale(1); 12 | } 13 | 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 1); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected vendor-prefixed property "-webkit-transform" (property-no-vendor-prefix)', 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | 'property-no-vendor-prefix', 47 | ], 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/rule-empty-line-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with rule-empty-line-before lint', () => { 9 | const invalidScss = ( 10 | `p { 11 | margin: 0; 12 | em { 13 | color: #f00; 14 | } 15 | } 16 | a { 17 | color: #f00; 18 | } 19 | `); 20 | 21 | let result; 22 | 23 | beforeEach(async () => { 24 | result = await stylelint.lint({ 25 | code: invalidScss, 26 | config, 27 | }); 28 | }); 29 | 30 | it('did error', () => { 31 | assert.equal(result.errored, true); 32 | }); 33 | 34 | it('flags warnings', () => { 35 | assert.equal(result.results[0].warnings.length, 2); 36 | }); 37 | 38 | it('correct warning text', () => { 39 | assert.deepEqual( 40 | result.results[0].warnings.map((w) => w.text), 41 | [ 42 | 'Expected empty line before rule (rule-empty-line-before)', 43 | 'Expected empty line before rule (rule-empty-line-before)', 44 | ], 45 | ); 46 | }); 47 | 48 | it('correct rule flagged', () => { 49 | assert.deepEqual( 50 | result.results[0].warnings.map((w) => w.rule), 51 | [ 52 | 'rule-empty-line-before', 53 | 'rule-empty-line-before', 54 | ], 55 | ); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /__tests__/scss-at-extend-no-missing-placeholder.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/at-extend-no-missing-placeholder lint', () => { 9 | const invalidScss = ( 10 | `.fatal { 11 | @extend .error; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected a placeholder selector (e.g. %placeholder) to be used in @extend (scss/at-extend-no-missing-placeholder)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'scss/at-extend-no-missing-placeholder', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/scss-at-function-pattern.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/at-function-pattern lint', () => { 9 | const invalidScss = ( 10 | `@function calculationFunction($some-number, $another-number) { 11 | @return $some-number + $another-number; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected @function name to match specified pattern (scss/at-function-pattern)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'scss/at-function-pattern', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid scss/at-function-pattern', () => { 52 | const validScss = ( 53 | `@function calculation-function($some-number, $another-number) { 54 | @return $some-number + $another-number; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/scss-at-import-partial-extension-disallowed-list.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/at-import-partial-extension-disallowed-list lint', () => { 9 | const invalidScss = ( 10 | `@import 'foo/_bar.scss'; 11 | @import '_bar.scss'; 12 | @import '_bar'; 13 | @import 'bar.scss'; 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 6); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 38 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 39 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 40 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 41 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 42 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 43 | ], 44 | ); 45 | }); 46 | 47 | it('correct rule flagged', () => { 48 | assert.deepEqual( 49 | result.results[0].warnings.map((w) => w.rule), 50 | [ 51 | 'scss/at-import-partial-extension-disallowed-list', 52 | 'scss/at-import-partial-extension-disallowed-list', 53 | 'scss/at-import-partial-extension-disallowed-list', 54 | 'scss/load-no-partial-leading-underscore', 55 | 'scss/load-no-partial-leading-underscore', 56 | 'scss/load-no-partial-leading-underscore', 57 | ], 58 | ); 59 | }); 60 | }); 61 | 62 | describe('does not flag warnings with valid scss/at-import-partial-extension-disallowed-list lint', () => { 63 | const validScss = ( 64 | `@import 'foo/bar'; 65 | @import 'bar'; 66 | `); 67 | 68 | let result; 69 | 70 | beforeEach(async () => { 71 | result = await stylelint.lint({ 72 | code: validScss, 73 | config, 74 | }); 75 | }); 76 | 77 | it('did not error', () => { 78 | assert.equal(result.errored, false); 79 | }); 80 | 81 | it('does not flag warnings', () => { 82 | assert.equal(result.results[0].warnings.length, 0); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /__tests__/scss-at-rule-no-unknown.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/at-rule-no-unknown lint', () => { 9 | const invalidScss = ( 10 | `@unknown { color: #fff; } 11 | 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 1); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected unknown at-rule "@unknown" (scss/at-rule-no-unknown)', 36 | ], 37 | ); 38 | }); 39 | 40 | it('correct rule flagged', () => { 41 | assert.deepEqual( 42 | result.results[0].warnings.map((w) => w.rule), 43 | [ 44 | 'scss/at-rule-no-unknown', 45 | ], 46 | ); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /__tests__/scss-dollar-variable-colon-space-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/dollar-variable-colon-space-after lint', () => { 9 | const invalidScss = ( 10 | `a { $var:10px;} 11 | 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 1); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Expected single space after ":" (scss/dollar-variable-colon-space-after)', 36 | ], 37 | ); 38 | }); 39 | 40 | it('correct rule flagged', () => { 41 | assert.deepEqual( 42 | result.results[0].warnings.map((w) => w.rule), 43 | [ 44 | 'scss/dollar-variable-colon-space-after' 45 | ], 46 | ); 47 | }); 48 | }); 49 | 50 | describe('does not flag warnings with valid scss/dollar-variable-colon-space-after', () => { 51 | const validScss = ( 52 | `a { $var: 10px;} 53 | 54 | `); 55 | 56 | let result; 57 | 58 | beforeEach(async () => { 59 | result = await stylelint.lint({ 60 | code: validScss, 61 | config, 62 | }); 63 | }); 64 | 65 | it('did not error', () => { 66 | assert.equal(result.errored, false); 67 | }); 68 | 69 | it('does not flag warnings', () => { 70 | assert.equal(result.results[0].warnings.length, 0); 71 | }); 72 | }); -------------------------------------------------------------------------------- /__tests__/scss-dollar-variable-colon-space-before.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/dollar-variable-colon-space-before lint', () => { 9 | const invalidScss = ( 10 | `a { $var : 10px;} 11 | 12 | `); 13 | 14 | let result; 15 | 16 | beforeEach(async () => { 17 | result = await stylelint.lint({ 18 | code: invalidScss, 19 | config, 20 | }); 21 | }); 22 | 23 | it('did error', () => { 24 | assert.equal(result.errored, true); 25 | }); 26 | 27 | it('flags warnings', () => { 28 | assert.equal(result.results[0].warnings.length, 1); 29 | }); 30 | 31 | it('correct warning text', () => { 32 | assert.deepEqual( 33 | result.results[0].warnings.map((w) => w.text), 34 | [ 35 | 'Unexpected whitespace before ":" (scss/dollar-variable-colon-space-before)', 36 | ], 37 | ); 38 | }); 39 | 40 | it('correct rule flagged', () => { 41 | assert.deepEqual( 42 | result.results[0].warnings.map((w) => w.rule), 43 | [ 44 | 'scss/dollar-variable-colon-space-before' 45 | ], 46 | ); 47 | }); 48 | }); 49 | 50 | describe('does not flag warnings with valid scss/dollar-variable-colon-space-after', () => { 51 | const validScss = ( 52 | `a { $var: 10px;} 53 | 54 | `); 55 | 56 | let result; 57 | 58 | beforeEach(async () => { 59 | result = await stylelint.lint({ 60 | code: validScss, 61 | config, 62 | }); 63 | }); 64 | 65 | it('did not error', () => { 66 | assert.equal(result.errored, false); 67 | }); 68 | 69 | it('does not flag warnings', () => { 70 | assert.equal(result.results[0].warnings.length, 0); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /__tests__/scss-dollar-variable-pattern.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with invalid scss/dollar-variable-pattern lint', () => { 9 | const invalidScss = ( 10 | `$myVar: 10px; 11 | `); 12 | 13 | let result; 14 | 15 | beforeEach(async () => { 16 | result = await stylelint.lint({ 17 | code: invalidScss, 18 | config, 19 | }); 20 | }); 21 | 22 | it('did error', () => { 23 | assert.equal(result.errored, true); 24 | }); 25 | 26 | it('flags warnings', () => { 27 | assert.equal(result.results[0].warnings.length, 1); 28 | }); 29 | 30 | it('correct warning text', () => { 31 | assert.deepEqual( 32 | result.results[0].warnings.map((w) => w.text), 33 | [ 34 | 'Expected $ variable name to match specified pattern (scss/dollar-variable-pattern)', 35 | ], 36 | ); 37 | }); 38 | 39 | it('correct rule flagged', () => { 40 | assert.deepEqual( 41 | result.results[0].warnings.map((w) => w.rule), 42 | [ 43 | 'scss/dollar-variable-pattern', 44 | ], 45 | ); 46 | }); 47 | }); 48 | 49 | describe('does not flag warnings with valid scss/dollar-variable-pattern lint', () => { 50 | const validScss = ( 51 | `$my-var: 10px; 52 | 53 | `); 54 | 55 | let result; 56 | 57 | beforeEach(async () => { 58 | result = await stylelint.lint({ 59 | code: validScss, 60 | config, 61 | }); 62 | }); 63 | 64 | it('did not error', () => { 65 | assert.equal(result.errored, false); 66 | }); 67 | 68 | it('does not flag warnings', () => { 69 | assert.equal(result.results[0].warnings.length, 0); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /__tests__/scss-load-no-partial-leading-underscore.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/load-no-partial-leading-underscore lint', () => { 9 | const invalidScss = ( 10 | `@import 'foo/_bar.scss'; 11 | @import '_bar.scss'; 12 | @import '_bar'; 13 | @import 'bar.scss'; 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 6); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 38 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 39 | 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', 40 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 41 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 42 | 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', 43 | ], 44 | ); 45 | }); 46 | 47 | it('correct rule flagged', () => { 48 | assert.deepEqual( 49 | result.results[0].warnings.map((w) => w.rule), 50 | [ 51 | 'scss/at-import-partial-extension-disallowed-list', 52 | 'scss/at-import-partial-extension-disallowed-list', 53 | 'scss/at-import-partial-extension-disallowed-list', 54 | 'scss/load-no-partial-leading-underscore', 55 | 'scss/load-no-partial-leading-underscore', 56 | 'scss/load-no-partial-leading-underscore', 57 | ], 58 | ); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /__tests__/scss-no-global-function-names.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/no-global-function-names lint', () => { 9 | const invalidScss = ( 10 | `a { 11 | background: adjust-color(#6b717f, $red: 15); 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected color.adjust instead of adjust-color (scss/no-global-function-names)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'scss/no-global-function-names', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/scss-percent-placeholder-pattern.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/percent-placeholder-pattern lint', () => { 9 | const invalidScss = ( 10 | `%placeHolder { 11 | color: #f00; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected %-placeholder "%placeHolder" to match specified pattern (scss/percent-placeholder-pattern)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'scss/percent-placeholder-pattern', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid scss/percent-placeholder-pattern lint', () => { 52 | const validScss = ( 53 | `%place-holder { 54 | color: #f00; 55 | } 56 | 57 | `); 58 | 59 | let result; 60 | 61 | beforeEach(async () => { 62 | result = await stylelint.lint({ 63 | code: validScss, 64 | config, 65 | }); 66 | }); 67 | 68 | it('did not error', () => { 69 | assert.equal(result.errored, false); 70 | }); 71 | 72 | it('does not flag warnings', () => { 73 | assert.equal(result.results[0].warnings.length, 0); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /__tests__/scss-selector-no-redundant-nesting-selector.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with scss/selector-no-redundant-nesting-selector lint', () => { 9 | const invalidScss = ( 10 | `.parentreference { 11 | & > .bar { 12 | color: #f00; 13 | } 14 | } 15 | `); 16 | 17 | let result; 18 | 19 | beforeEach(async () => { 20 | result = await stylelint.lint({ 21 | code: invalidScss, 22 | config, 23 | }); 24 | }); 25 | 26 | it('did error', () => { 27 | assert.equal(result.errored, true); 28 | }); 29 | 30 | it('flags warnings', () => { 31 | assert.equal(result.results[0].warnings.length, 1); 32 | }); 33 | 34 | it('correct warning text', () => { 35 | assert.deepEqual( 36 | result.results[0].warnings.map((w) => w.text), 37 | [ 38 | 'Unnecessary nesting selector (&) (scss/selector-no-redundant-nesting-selector)', 39 | ], 40 | ); 41 | }); 42 | 43 | it('correct rule flagged', () => { 44 | assert.deepEqual( 45 | result.results[0].warnings.map((w) => w.rule), 46 | [ 47 | 'scss/selector-no-redundant-nesting-selector', 48 | ], 49 | ); 50 | }); 51 | }); 52 | 53 | describe('does not flag warnings with valid scss/selector-no-redundant-nesting-selector lint', () => { 54 | const validScss = ( 55 | `.parentreference { 56 | > .bar { 57 | color: #f00; 58 | } 59 | } 60 | 61 | `); 62 | 63 | let result; 64 | 65 | beforeEach(async () => { 66 | result = await stylelint.lint({ 67 | code: validScss, 68 | config, 69 | }); 70 | }); 71 | 72 | it('did not error', () => { 73 | assert.equal(result.errored, false); 74 | }); 75 | 76 | it('does not flag warnings', () => { 77 | assert.equal(result.results[0].warnings.length, 0); 78 | }); 79 | }); -------------------------------------------------------------------------------- /__tests__/selector-class-pattern.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-class-pattern lint', () => { 9 | const invalidScss = ( 10 | `.Foo { 11 | color: #f00; 12 | } 13 | 14 | .fooBar { 15 | color: #f00; 16 | } 17 | 18 | .fooBar5 { 19 | color: #f00; 20 | } 21 | 22 | .foo-Bar { 23 | color: #f00; 24 | } 25 | 26 | .foo-Bar---baz { 27 | color: #f00; 28 | } 29 | `); 30 | 31 | let result; 32 | 33 | beforeEach(async () => { 34 | result = await stylelint.lint({ 35 | code: invalidScss, 36 | config, 37 | }); 38 | }); 39 | 40 | it('did error', () => { 41 | assert.equal(result.errored, true); 42 | }); 43 | 44 | it('flags warnings', () => { 45 | assert.equal(result.results[0].warnings.length, 5); 46 | }); 47 | 48 | it('correct warning text', () => { 49 | assert.deepEqual( 50 | result.results[0].warnings.map((w) => w.text), 51 | [ 52 | 'Selector should be written in lowercase with hyphens (selector-class-pattern)', 53 | 'Selector should be written in lowercase with hyphens (selector-class-pattern)', 54 | 'Selector should be written in lowercase with hyphens (selector-class-pattern)', 55 | 'Selector should be written in lowercase with hyphens (selector-class-pattern)', 56 | 'Selector should be written in lowercase with hyphens (selector-class-pattern)', 57 | ], 58 | ); 59 | }); 60 | 61 | it('correct rule flagged', () => { 62 | assert.deepEqual( 63 | result.results[0].warnings.map((w) => w.rule), 64 | [ 65 | 'selector-class-pattern', 66 | 'selector-class-pattern', 67 | 'selector-class-pattern', 68 | 'selector-class-pattern', 69 | 'selector-class-pattern', 70 | ], 71 | ); 72 | }); 73 | }); 74 | 75 | describe('does not flag warnings with valid selector-class-pattern', () => { 76 | const validScss = ( 77 | `.selector-format { 78 | color: #f00; 79 | } 80 | 81 | .foo { 82 | color: #f00; 83 | } 84 | 85 | .foo5 { 86 | color: #f00; 87 | } 88 | 89 | .foo-5 { 90 | color: #f00; 91 | } 92 | 93 | .foo--5 { 94 | color: #f00; 95 | } 96 | 97 | .foo-bar { 98 | color: #f00; 99 | } 100 | 101 | .foo--bar { 102 | color: #f00; 103 | } 104 | 105 | .foo-bar-5 { 106 | color: #f00; 107 | } 108 | 109 | .foo-bar-baz { 110 | color: #f00; 111 | } 112 | 113 | .foo-bar--baz { 114 | color: #f00; 115 | } 116 | 117 | .foo-bar-baz--qux { 118 | color: #f00; 119 | } 120 | 121 | .foo-bar--baz--qux { 122 | color: #f00; 123 | } 124 | 125 | .foo--bar--baz--qux { 126 | color: #f00; 127 | } 128 | 129 | .u-hidden { 130 | color: #f00; 131 | } 132 | 133 | .u-class-name { 134 | color: #f00; 135 | } 136 | 137 | .is-stateclass { 138 | color: #f00; 139 | } 140 | 141 | .has-state-class { 142 | color: #f00; 143 | } 144 | 145 | .js-dependantclass { 146 | color: #f00; 147 | } 148 | 149 | .namespace-u-text-center { 150 | color: #f00; 151 | } 152 | 153 | .namespace-u-sm-size11of12 { 154 | color: #f00; 155 | } 156 | 157 | .u-foobar17 { 158 | color: #f00; 159 | } 160 | 161 | .u-16by9 { 162 | color: #f00; 163 | } 164 | 165 | `); 166 | 167 | let result; 168 | 169 | beforeEach(async () => { 170 | result = await stylelint.lint({ 171 | code: validScss, 172 | config, 173 | }); 174 | }); 175 | 176 | it('did not error', () => { 177 | assert.equal(result.errored, false); 178 | }); 179 | 180 | it('does not flag warnings', () => { 181 | assert.equal(result.results[0].warnings.length, 0); 182 | }); 183 | }); 184 | -------------------------------------------------------------------------------- /__tests__/selector-list-comma-newline-after.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-list-comma-newline-after lint', () => { 9 | const invalidScss = ( 10 | `a, b { 11 | color: #fff; 12 | } 13 | 14 | a 15 | , b { 16 | color: #000; 17 | } 18 | `); 19 | 20 | let result; 21 | 22 | beforeEach(async () => { 23 | result = await stylelint.lint({ 24 | code: invalidScss, 25 | config, 26 | }); 27 | }); 28 | 29 | it('did error', () => { 30 | assert.equal(result.errored, true); 31 | }); 32 | 33 | it('flags warnings', () => { 34 | assert.equal(result.results[0].warnings.length, 2); 35 | }); 36 | 37 | it('correct warning text', () => { 38 | assert.deepEqual( 39 | result.results[0].warnings.map((w) => w.text), 40 | [ 41 | 'Expected newline after "," (@stylistic/selector-list-comma-newline-after)', 42 | 'Expected newline after "," (@stylistic/selector-list-comma-newline-after)' 43 | ], 44 | ); 45 | }); 46 | 47 | it('correct rule flagged', () => { 48 | assert.deepEqual( 49 | result.results[0].warnings.map((w) => w.rule), 50 | [ 51 | '@stylistic/selector-list-comma-newline-after', 52 | '@stylistic/selector-list-comma-newline-after' 53 | ], 54 | ); 55 | }); 56 | }); 57 | 58 | describe('does not flag warnings with valid selector-list-comma-newline-after', () => { 59 | const validScss = ( 60 | `a, 61 | b { 62 | color: #fff; 63 | } 64 | 65 | `); 66 | 67 | let result; 68 | 69 | beforeEach(async () => { 70 | result = await stylelint.lint({ 71 | code: validScss, 72 | config, 73 | }); 74 | }); 75 | 76 | it('did not error', () => { 77 | assert.equal(result.errored, false); 78 | }); 79 | 80 | it('does not flag warnings', () => { 81 | assert.equal(result.results[0].warnings.length, 0); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /__tests__/selector-max-compound-selectors.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-max-compound-selectors lint', () => { 9 | const invalidScss = ( 10 | `.one .two .three > .four { 11 | color: #f00; 12 | } 13 | 14 | .one .two { 15 | .three > .four { 16 | color: #f00; 17 | } 18 | } 19 | `); 20 | 21 | let result; 22 | 23 | beforeEach(async () => { 24 | result = await stylelint.lint({ 25 | code: invalidScss, 26 | config, 27 | }); 28 | }); 29 | 30 | it('did error', () => { 31 | assert.equal(result.errored, true); 32 | }); 33 | 34 | it('flags warnings', () => { 35 | assert.equal(result.results[0].warnings.length, 2); 36 | }); 37 | 38 | it('correct warning text', () => { 39 | assert.deepEqual( 40 | result.results[0].warnings.map((w) => w.text), 41 | [ 42 | 'Expected ".one .two .three > .four" to have no more than 3 compound selectors (selector-max-compound-selectors)', 43 | 'Expected ".three > .four" to have no more than 3 compound selectors (selector-max-compound-selectors)' 44 | ], 45 | ); 46 | }); 47 | 48 | it('correct rule flagged', () => { 49 | assert.deepEqual( 50 | result.results[0].warnings.map((w) => w.rule), 51 | [ 52 | 'selector-max-compound-selectors', 53 | 'selector-max-compound-selectors', 54 | ], 55 | ); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /__tests__/selector-max-id.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-max-id lint', () => { 9 | const invalidScss = ( 10 | `#id-selector { 11 | color: #f00; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected "#id-selector" to have no more than 0 ID selectors (selector-max-id)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'selector-max-id', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__tests__/selector-no-qualifying-type.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-no-qualifying-type lint', () => { 9 | const invalidScss = ( 10 | `div#thing { 11 | color: #f00; 12 | } 13 | 14 | ul.list { 15 | color: #f00; 16 | } 17 | 18 | ul li.item { 19 | color: #f00; 20 | } 21 | 22 | a[href='place'] { 23 | color: #f00; 24 | } 25 | `); 26 | 27 | let result; 28 | 29 | beforeEach(async () => { 30 | result = await stylelint.lint({ 31 | code: invalidScss, 32 | config, 33 | }); 34 | }); 35 | 36 | it('did error', () => { 37 | assert.equal(result.errored, true); 38 | }); 39 | 40 | it('flags warnings', () => { 41 | assert.equal(result.results[0].warnings.length, 5); 42 | }); 43 | 44 | it('correct warning text', () => { 45 | assert.deepEqual( 46 | result.results[0].warnings.map((w) => w.text), 47 | [ 48 | 'Expected "div#thing" to have no more than 0 ID selectors (selector-max-id)', 49 | 'Unexpected qualifying type selector "div#thing" (selector-no-qualifying-type)', 50 | 'Unexpected qualifying type selector "ul.list" (selector-no-qualifying-type)', 51 | 'Unexpected qualifying type selector "li.item" (selector-no-qualifying-type)', 52 | 'Unexpected qualifying type selector "a[href=\'place\']" (selector-no-qualifying-type)' 53 | ], 54 | ); 55 | }); 56 | 57 | it('correct rule flagged', () => { 58 | assert.deepEqual( 59 | result.results[0].warnings.map((w) => w.rule), 60 | [ 61 | 'selector-max-id', 62 | 'selector-no-qualifying-type', 63 | 'selector-no-qualifying-type', 64 | 'selector-no-qualifying-type', 65 | 'selector-no-qualifying-type', 66 | ], 67 | ); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /__tests__/selector-no-vendor-prefix.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-no-vendor-prefix lint', () => { 9 | const invalidScss = ( 10 | `::-moz-placeholder { 11 | color: #f00; 12 | } 13 | 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 1); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected vendor-prefixed selector "::-moz-placeholder" (selector-no-vendor-prefix)' 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | 'selector-no-vendor-prefix', 47 | ], 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/selector-pseudo-element-colon-notation.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-pseudo-element-colon-notation lint', () => { 9 | const invalidScss = ( 10 | `p:before { 11 | content: '>'; 12 | } 13 | 14 | p::hover { 15 | color: #f00; 16 | } 17 | `); 18 | 19 | let result; 20 | 21 | beforeEach(async () => { 22 | result = await stylelint.lint({ 23 | code: invalidScss, 24 | config, 25 | }); 26 | }); 27 | 28 | it('did error', () => { 29 | assert.equal(result.errored, true); 30 | }); 31 | 32 | it('flags warnings', () => { 33 | assert.equal(result.results[0].warnings.length, 2); 34 | }); 35 | 36 | it('correct warning text', () => { 37 | assert.deepEqual( 38 | result.results[0].warnings.map((w) => w.text), 39 | [ 40 | 'Expected double colon pseudo-element notation (selector-pseudo-element-colon-notation)', 41 | 'Unexpected unknown pseudo-element selector "::hover" (selector-pseudo-element-no-unknown)' 42 | ], 43 | ); 44 | }); 45 | 46 | it('correct rule flagged', () => { 47 | assert.deepEqual( 48 | result.results[0].warnings.map((w) => w.rule), 49 | [ 50 | 'selector-pseudo-element-colon-notation', 51 | 'selector-pseudo-element-no-unknown', 52 | ], 53 | ); 54 | }); 55 | }); 56 | 57 | describe('does not flag warnings with valid selector-pseudo-element-colon-notation lint', () => { 58 | const validScss = ( 59 | `a::before { 60 | content: '>'; 61 | } 62 | 63 | a:hover { 64 | color: #f00; 65 | } 66 | 67 | `); 68 | 69 | let result; 70 | 71 | beforeEach(async () => { 72 | result = await stylelint.lint({ 73 | code: validScss, 74 | config, 75 | }); 76 | }); 77 | 78 | it('did not error', () => { 79 | assert.equal(result.errored, false); 80 | }); 81 | 82 | it('does not flag warnings', () => { 83 | assert.equal(result.results[0].warnings.length, 0); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /__tests__/selector-pseudo-element-no-unknown.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with selector-pseudo-element-no-unknown lint', () => { 9 | const invalidScss = ( 10 | `p::hover { 11 | color: #f00; 12 | } 13 | 14 | `); 15 | 16 | let result; 17 | 18 | beforeEach(async () => { 19 | result = await stylelint.lint({ 20 | code: invalidScss, 21 | config, 22 | }); 23 | }); 24 | 25 | it('did error', () => { 26 | assert.equal(result.errored, true); 27 | }); 28 | 29 | it('flags warnings', () => { 30 | assert.equal(result.results[0].warnings.length, 1); 31 | }); 32 | 33 | it('correct warning text', () => { 34 | assert.deepEqual( 35 | result.results[0].warnings.map((w) => w.text), 36 | [ 37 | 'Unexpected unknown pseudo-element selector "::hover" (selector-pseudo-element-no-unknown)' 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | 'selector-pseudo-element-no-unknown', 47 | ], 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/shorthand-property-no-redundant-values.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with shorthand-property-no-redundant-values lint', () => { 9 | const invalidScss = ( 10 | `.shorthand { 11 | margin: 1px 1px 1px 1px; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected "1px 1px 1px 1px" to be "1px" (shorthand-property-no-redundant-values)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'shorthand-property-no-redundant-values', 46 | ], 47 | ); 48 | }); 49 | }); 50 | 51 | describe('does not flag warnings with valid shorthand-property-no-redundant-values', () => { 52 | const validScss = ( 53 | `.shorthand { 54 | margin: 1px; 55 | } 56 | `); 57 | 58 | let result; 59 | 60 | beforeEach(async () => { 61 | result = await stylelint.lint({ 62 | code: validScss, 63 | config, 64 | }); 65 | }); 66 | 67 | it('did not error', () => { 68 | assert.equal(result.errored, false); 69 | }); 70 | 71 | it('does not flag warnings', () => { 72 | assert.equal(result.results[0].warnings.length, 0); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__tests__/string-quotes.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with string-quotes lint', () => { 9 | const invalidScss = ( 10 | `.test-selector[data-testid="foo"] { 11 | content: "x"; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 2); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Expected single quotes (@stylistic/string-quotes)', 37 | 'Expected single quotes (@stylistic/string-quotes)' 38 | ], 39 | ); 40 | }); 41 | 42 | it('correct rule flagged', () => { 43 | assert.deepEqual( 44 | result.results[0].warnings.map((w) => w.rule), 45 | [ 46 | '@stylistic/string-quotes', 47 | '@stylistic/string-quotes' 48 | ], 49 | ); 50 | }); 51 | }); 52 | 53 | describe('does not flag warnings with valid string-quotes', () => { 54 | const validScss = ( 55 | `.test-selector { 56 | content: 'test'; 57 | } 58 | 59 | 60 | `); 61 | 62 | let result; 63 | 64 | beforeEach(async () => { 65 | result = await stylelint.lint({ 66 | code: validScss, 67 | config, 68 | }); 69 | }); 70 | 71 | it('did not error', () => { 72 | assert.equal(result.errored, false); 73 | }); 74 | 75 | it('does not flag warnings', () => { 76 | assert.equal(result.results[0].warnings.length, 0); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /__tests__/value-no-vendor-prefix.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | 4 | import stylelint from 'stylelint'; 5 | 6 | import config from '../index.js'; 7 | 8 | describe('flags warnings with value-no-vendor-prefix lint', () => { 9 | const invalidScss = ( 10 | `.value-prefix { 11 | display: -webkit-flex; 12 | } 13 | `); 14 | 15 | let result; 16 | 17 | beforeEach(async () => { 18 | result = await stylelint.lint({ 19 | code: invalidScss, 20 | config, 21 | }); 22 | }); 23 | 24 | it('did error', () => { 25 | assert.equal(result.errored, true); 26 | }); 27 | 28 | it('flags warnings', () => { 29 | assert.equal(result.results[0].warnings.length, 1); 30 | }); 31 | 32 | it('correct warning text', () => { 33 | assert.deepEqual( 34 | result.results[0].warnings.map((w) => w.text), 35 | [ 36 | 'Unexpected vendor-prefixed value "-webkit-flex" (value-no-vendor-prefix)', 37 | ], 38 | ); 39 | }); 40 | 41 | it('correct rule flagged', () => { 42 | assert.deepEqual( 43 | result.results[0].warnings.map((w) => w.rule), 44 | [ 45 | 'value-no-vendor-prefix', 46 | ], 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugins": [ 3 | "stylelint-scss", 4 | "@stylistic/stylelint-plugin", 5 | ], 6 | "customSyntax": "postcss-scss", 7 | "rules": { 8 | "at-rule-disallowed-list": ["debug"], 9 | "at-rule-no-unknown": null, 10 | "at-rule-no-vendor-prefix": true, 11 | "block-no-empty": true, 12 | "color-hex-length": "short", 13 | "color-named": "never", 14 | "color-no-invalid-hex": true, 15 | "declaration-block-single-line-max-declarations": 1, 16 | "declaration-property-value-disallowed-list": { 17 | "border": ["none"], 18 | "border-top": ["none"], 19 | "border-right": ["none"], 20 | "border-bottom": ["none"], 21 | "border-left": ["none"] 22 | }, 23 | "function-url-quotes": "always", 24 | "length-zero-no-unit": true, 25 | "max-nesting-depth": [ 26 | 1, 27 | { 28 | "ignoreAtRules": [ 29 | "each", 30 | "media", 31 | "supports", 32 | "include" 33 | ] 34 | } 35 | ], 36 | "media-feature-name-no-vendor-prefix": true, 37 | "property-no-unknown": true, 38 | "property-no-vendor-prefix": true, 39 | "rule-empty-line-before": [ 40 | "always-multi-line", 41 | { 42 | "except": ["first-nested"], 43 | "ignore": ["after-comment"] 44 | } 45 | ], 46 | "selector-class-pattern": [ 47 | "^[a-z0-9\\-]+$", 48 | { 49 | "message": 50 | "Selector should be written in lowercase with hyphens (selector-class-pattern)" 51 | } 52 | ], 53 | "selector-max-compound-selectors": 3, 54 | "selector-max-id": 0, 55 | "selector-no-qualifying-type": true, 56 | "selector-no-vendor-prefix": true, 57 | "selector-pseudo-element-colon-notation": "double", 58 | "selector-pseudo-element-no-unknown": true, 59 | "shorthand-property-no-redundant-values": true, 60 | "value-no-vendor-prefix": true, 61 | "@stylistic/block-opening-brace-space-before": "always", 62 | "@stylistic/color-hex-case": "lower", 63 | "@stylistic/declaration-bang-space-after": "never", 64 | "@stylistic/declaration-bang-space-before": "always", 65 | "@stylistic/declaration-block-semicolon-newline-after": "always", 66 | "@stylistic/declaration-block-semicolon-space-before": "never", 67 | "@stylistic/declaration-block-trailing-semicolon": "always", 68 | "@stylistic/declaration-colon-space-after": "always-single-line", 69 | "@stylistic/declaration-colon-space-before": "never", 70 | "@stylistic/function-comma-space-after": "always-single-line", 71 | "@stylistic/function-parentheses-space-inside": "never", 72 | "@stylistic/indentation": 2, 73 | "@stylistic/media-feature-parentheses-space-inside": "never", 74 | "@stylistic/no-missing-end-of-source-newline": true, 75 | "@stylistic/number-leading-zero": "always", 76 | "@stylistic/number-no-trailing-zeros": true, 77 | "@stylistic/selector-list-comma-newline-after": "always", 78 | "@stylistic/string-quotes": "single", 79 | "scss/at-extend-no-missing-placeholder": true, 80 | "scss/at-function-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", 81 | "scss/at-import-partial-extension-disallowed-list": ["scss"], 82 | "scss/at-rule-no-unknown": true, 83 | "scss/dollar-variable-colon-space-after": "always", 84 | "scss/dollar-variable-colon-space-before": "never", 85 | "scss/dollar-variable-pattern": "^[_]?[a-z]+([a-z0-9-]+[a-z0-9]+)?$", 86 | "scss/load-no-partial-leading-underscore": true, 87 | "scss/no-global-function-names": true, 88 | "scss/percent-placeholder-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", 89 | "scss/selector-no-redundant-nesting-selector": true, 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-config-sass-guidelines", 3 | "version": "12.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "stylelint-config-sass-guidelines", 9 | "version": "12.1.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@stylistic/stylelint-plugin": "^3.0.1", 13 | "postcss-scss": "^4.0.9", 14 | "stylelint-scss": "^6.2.1" 15 | }, 16 | "devDependencies": { 17 | "postcss": "^8.4.21", 18 | "stylelint": "^16.1.0" 19 | }, 20 | "engines": { 21 | "node": ">=18.12.0" 22 | }, 23 | "peerDependencies": { 24 | "postcss": "^8.4.21", 25 | "stylelint": "^16.1.0" 26 | } 27 | }, 28 | "node_modules/@babel/code-frame": { 29 | "version": "7.26.2", 30 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", 31 | "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", 32 | "license": "MIT", 33 | "dependencies": { 34 | "@babel/helper-validator-identifier": "^7.25.9", 35 | "js-tokens": "^4.0.0", 36 | "picocolors": "^1.0.0" 37 | }, 38 | "engines": { 39 | "node": ">=6.9.0" 40 | } 41 | }, 42 | "node_modules/@babel/helper-validator-identifier": { 43 | "version": "7.25.9", 44 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", 45 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", 46 | "license": "MIT", 47 | "engines": { 48 | "node": ">=6.9.0" 49 | } 50 | }, 51 | "node_modules/@csstools/css-parser-algorithms": { 52 | "version": "3.0.4", 53 | "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", 54 | "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", 55 | "funding": [ 56 | { 57 | "type": "github", 58 | "url": "https://github.com/sponsors/csstools" 59 | }, 60 | { 61 | "type": "opencollective", 62 | "url": "https://opencollective.com/csstools" 63 | } 64 | ], 65 | "license": "MIT", 66 | "engines": { 67 | "node": ">=18" 68 | }, 69 | "peerDependencies": { 70 | "@csstools/css-tokenizer": "^3.0.3" 71 | } 72 | }, 73 | "node_modules/@csstools/css-tokenizer": { 74 | "version": "3.0.3", 75 | "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", 76 | "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", 77 | "funding": [ 78 | { 79 | "type": "github", 80 | "url": "https://github.com/sponsors/csstools" 81 | }, 82 | { 83 | "type": "opencollective", 84 | "url": "https://opencollective.com/csstools" 85 | } 86 | ], 87 | "license": "MIT", 88 | "engines": { 89 | "node": ">=18" 90 | } 91 | }, 92 | "node_modules/@csstools/media-query-list-parser": { 93 | "version": "3.0.1", 94 | "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz", 95 | "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==", 96 | "funding": [ 97 | { 98 | "type": "github", 99 | "url": "https://github.com/sponsors/csstools" 100 | }, 101 | { 102 | "type": "opencollective", 103 | "url": "https://opencollective.com/csstools" 104 | } 105 | ], 106 | "license": "MIT", 107 | "engines": { 108 | "node": ">=18" 109 | }, 110 | "peerDependencies": { 111 | "@csstools/css-parser-algorithms": "^3.0.1", 112 | "@csstools/css-tokenizer": "^3.0.1" 113 | } 114 | }, 115 | "node_modules/@dual-bundle/import-meta-resolve": { 116 | "version": "4.1.0", 117 | "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", 118 | "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", 119 | "license": "MIT", 120 | "funding": { 121 | "type": "github", 122 | "url": "https://github.com/sponsors/wooorm" 123 | } 124 | }, 125 | "node_modules/@keyv/serialize": { 126 | "version": "1.0.2", 127 | "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.0.2.tgz", 128 | "integrity": "sha512-+E/LyaAeuABniD/RvUezWVXKpeuvwLEA9//nE9952zBaOdBd2mQ3pPoM8cUe2X6IcMByfuSLzmYqnYshG60+HQ==", 129 | "license": "MIT", 130 | "dependencies": { 131 | "buffer": "^6.0.3" 132 | } 133 | }, 134 | "node_modules/@nodelib/fs.scandir": { 135 | "version": "2.1.5", 136 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 137 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 138 | "license": "MIT", 139 | "dependencies": { 140 | "@nodelib/fs.stat": "2.0.5", 141 | "run-parallel": "^1.1.9" 142 | }, 143 | "engines": { 144 | "node": ">= 8" 145 | } 146 | }, 147 | "node_modules/@nodelib/fs.stat": { 148 | "version": "2.0.5", 149 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 150 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 151 | "license": "MIT", 152 | "engines": { 153 | "node": ">= 8" 154 | } 155 | }, 156 | "node_modules/@nodelib/fs.walk": { 157 | "version": "1.2.8", 158 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 159 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 160 | "license": "MIT", 161 | "dependencies": { 162 | "@nodelib/fs.scandir": "2.1.5", 163 | "fastq": "^1.6.0" 164 | }, 165 | "engines": { 166 | "node": ">= 8" 167 | } 168 | }, 169 | "node_modules/@stylistic/stylelint-plugin": { 170 | "version": "3.1.1", 171 | "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz", 172 | "integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==", 173 | "license": "MIT", 174 | "dependencies": { 175 | "@csstools/css-parser-algorithms": "^3.0.1", 176 | "@csstools/css-tokenizer": "^3.0.1", 177 | "@csstools/media-query-list-parser": "^3.0.1", 178 | "is-plain-object": "^5.0.0", 179 | "postcss-selector-parser": "^6.1.2", 180 | "postcss-value-parser": "^4.2.0", 181 | "style-search": "^0.1.0", 182 | "stylelint": "^16.8.2" 183 | }, 184 | "engines": { 185 | "node": "^18.12 || >=20.9" 186 | }, 187 | "peerDependencies": { 188 | "stylelint": "^16.8.0" 189 | } 190 | }, 191 | "node_modules/ajv": { 192 | "version": "8.17.1", 193 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", 194 | "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", 195 | "license": "MIT", 196 | "dependencies": { 197 | "fast-deep-equal": "^3.1.3", 198 | "fast-uri": "^3.0.1", 199 | "json-schema-traverse": "^1.0.0", 200 | "require-from-string": "^2.0.2" 201 | }, 202 | "funding": { 203 | "type": "github", 204 | "url": "https://github.com/sponsors/epoberezkin" 205 | } 206 | }, 207 | "node_modules/ansi-regex": { 208 | "version": "5.0.1", 209 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 210 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 211 | "license": "MIT", 212 | "engines": { 213 | "node": ">=8" 214 | } 215 | }, 216 | "node_modules/ansi-styles": { 217 | "version": "4.3.0", 218 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 219 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 220 | "license": "MIT", 221 | "dependencies": { 222 | "color-convert": "^2.0.1" 223 | }, 224 | "engines": { 225 | "node": ">=8" 226 | }, 227 | "funding": { 228 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 229 | } 230 | }, 231 | "node_modules/argparse": { 232 | "version": "2.0.1", 233 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 234 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 235 | "license": "Python-2.0" 236 | }, 237 | "node_modules/array-union": { 238 | "version": "2.1.0", 239 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 240 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 241 | "license": "MIT", 242 | "engines": { 243 | "node": ">=8" 244 | } 245 | }, 246 | "node_modules/astral-regex": { 247 | "version": "2.0.0", 248 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", 249 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", 250 | "license": "MIT", 251 | "engines": { 252 | "node": ">=8" 253 | } 254 | }, 255 | "node_modules/balanced-match": { 256 | "version": "2.0.0", 257 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", 258 | "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", 259 | "license": "MIT" 260 | }, 261 | "node_modules/base64-js": { 262 | "version": "1.5.1", 263 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 264 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 265 | "funding": [ 266 | { 267 | "type": "github", 268 | "url": "https://github.com/sponsors/feross" 269 | }, 270 | { 271 | "type": "patreon", 272 | "url": "https://www.patreon.com/feross" 273 | }, 274 | { 275 | "type": "consulting", 276 | "url": "https://feross.org/support" 277 | } 278 | ], 279 | "license": "MIT" 280 | }, 281 | "node_modules/braces": { 282 | "version": "3.0.3", 283 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 284 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 285 | "license": "MIT", 286 | "dependencies": { 287 | "fill-range": "^7.1.1" 288 | }, 289 | "engines": { 290 | "node": ">=8" 291 | } 292 | }, 293 | "node_modules/buffer": { 294 | "version": "6.0.3", 295 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 296 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 297 | "funding": [ 298 | { 299 | "type": "github", 300 | "url": "https://github.com/sponsors/feross" 301 | }, 302 | { 303 | "type": "patreon", 304 | "url": "https://www.patreon.com/feross" 305 | }, 306 | { 307 | "type": "consulting", 308 | "url": "https://feross.org/support" 309 | } 310 | ], 311 | "license": "MIT", 312 | "dependencies": { 313 | "base64-js": "^1.3.1", 314 | "ieee754": "^1.2.1" 315 | } 316 | }, 317 | "node_modules/cacheable": { 318 | "version": "1.8.7", 319 | "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.8.7.tgz", 320 | "integrity": "sha512-AbfG7dAuYNjYxFUtL1lAqmlWdxczCJ47w7cFjhGcnGnUdwSo6VgmSojfoW3tUI12HUkgTJ5kqj78yyq6TsFtlg==", 321 | "license": "MIT", 322 | "dependencies": { 323 | "hookified": "^1.6.0", 324 | "keyv": "^5.2.3" 325 | } 326 | }, 327 | "node_modules/callsites": { 328 | "version": "3.1.0", 329 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 330 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 331 | "license": "MIT", 332 | "engines": { 333 | "node": ">=6" 334 | } 335 | }, 336 | "node_modules/color-convert": { 337 | "version": "2.0.1", 338 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 339 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 340 | "license": "MIT", 341 | "dependencies": { 342 | "color-name": "~1.1.4" 343 | }, 344 | "engines": { 345 | "node": ">=7.0.0" 346 | } 347 | }, 348 | "node_modules/color-name": { 349 | "version": "1.1.4", 350 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 351 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 352 | "license": "MIT" 353 | }, 354 | "node_modules/colord": { 355 | "version": "2.9.3", 356 | "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", 357 | "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", 358 | "license": "MIT" 359 | }, 360 | "node_modules/cosmiconfig": { 361 | "version": "9.0.0", 362 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", 363 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", 364 | "license": "MIT", 365 | "dependencies": { 366 | "env-paths": "^2.2.1", 367 | "import-fresh": "^3.3.0", 368 | "js-yaml": "^4.1.0", 369 | "parse-json": "^5.2.0" 370 | }, 371 | "engines": { 372 | "node": ">=14" 373 | }, 374 | "funding": { 375 | "url": "https://github.com/sponsors/d-fischer" 376 | }, 377 | "peerDependencies": { 378 | "typescript": ">=4.9.5" 379 | }, 380 | "peerDependenciesMeta": { 381 | "typescript": { 382 | "optional": true 383 | } 384 | } 385 | }, 386 | "node_modules/css-functions-list": { 387 | "version": "3.2.3", 388 | "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", 389 | "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", 390 | "license": "MIT", 391 | "engines": { 392 | "node": ">=12 || >=16" 393 | } 394 | }, 395 | "node_modules/css-tree": { 396 | "version": "3.1.0", 397 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", 398 | "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", 399 | "license": "MIT", 400 | "dependencies": { 401 | "mdn-data": "2.12.2", 402 | "source-map-js": "^1.0.1" 403 | }, 404 | "engines": { 405 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 406 | } 407 | }, 408 | "node_modules/cssesc": { 409 | "version": "3.0.0", 410 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 411 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 412 | "license": "MIT", 413 | "bin": { 414 | "cssesc": "bin/cssesc" 415 | }, 416 | "engines": { 417 | "node": ">=4" 418 | } 419 | }, 420 | "node_modules/debug": { 421 | "version": "4.4.0", 422 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 423 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 424 | "license": "MIT", 425 | "dependencies": { 426 | "ms": "^2.1.3" 427 | }, 428 | "engines": { 429 | "node": ">=6.0" 430 | }, 431 | "peerDependenciesMeta": { 432 | "supports-color": { 433 | "optional": true 434 | } 435 | } 436 | }, 437 | "node_modules/dir-glob": { 438 | "version": "3.0.1", 439 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 440 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 441 | "license": "MIT", 442 | "dependencies": { 443 | "path-type": "^4.0.0" 444 | }, 445 | "engines": { 446 | "node": ">=8" 447 | } 448 | }, 449 | "node_modules/emoji-regex": { 450 | "version": "8.0.0", 451 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 452 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 453 | "license": "MIT" 454 | }, 455 | "node_modules/env-paths": { 456 | "version": "2.2.1", 457 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", 458 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", 459 | "license": "MIT", 460 | "engines": { 461 | "node": ">=6" 462 | } 463 | }, 464 | "node_modules/error-ex": { 465 | "version": "1.3.2", 466 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 467 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 468 | "license": "MIT", 469 | "dependencies": { 470 | "is-arrayish": "^0.2.1" 471 | } 472 | }, 473 | "node_modules/fast-deep-equal": { 474 | "version": "3.1.3", 475 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 476 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 477 | "license": "MIT" 478 | }, 479 | "node_modules/fast-glob": { 480 | "version": "3.3.3", 481 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 482 | "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 483 | "license": "MIT", 484 | "dependencies": { 485 | "@nodelib/fs.stat": "^2.0.2", 486 | "@nodelib/fs.walk": "^1.2.3", 487 | "glob-parent": "^5.1.2", 488 | "merge2": "^1.3.0", 489 | "micromatch": "^4.0.8" 490 | }, 491 | "engines": { 492 | "node": ">=8.6.0" 493 | } 494 | }, 495 | "node_modules/fast-uri": { 496 | "version": "3.0.5", 497 | "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz", 498 | "integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==", 499 | "funding": [ 500 | { 501 | "type": "github", 502 | "url": "https://github.com/sponsors/fastify" 503 | }, 504 | { 505 | "type": "opencollective", 506 | "url": "https://opencollective.com/fastify" 507 | } 508 | ], 509 | "license": "BSD-3-Clause" 510 | }, 511 | "node_modules/fastest-levenshtein": { 512 | "version": "1.0.16", 513 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", 514 | "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", 515 | "license": "MIT", 516 | "engines": { 517 | "node": ">= 4.9.1" 518 | } 519 | }, 520 | "node_modules/fastq": { 521 | "version": "1.18.0", 522 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", 523 | "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", 524 | "license": "ISC", 525 | "dependencies": { 526 | "reusify": "^1.0.4" 527 | } 528 | }, 529 | "node_modules/file-entry-cache": { 530 | "version": "10.0.5", 531 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.5.tgz", 532 | "integrity": "sha512-umpQsJrBNsdMDgreSryMEXvJh66XeLtZUwA8Gj7rHGearGufUFv6rB/bcXRFsiGWw/VeSUgUofF4Rf2UKEOrTA==", 533 | "license": "MIT", 534 | "dependencies": { 535 | "flat-cache": "^6.1.5" 536 | } 537 | }, 538 | "node_modules/fill-range": { 539 | "version": "7.1.1", 540 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 541 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 542 | "license": "MIT", 543 | "dependencies": { 544 | "to-regex-range": "^5.0.1" 545 | }, 546 | "engines": { 547 | "node": ">=8" 548 | } 549 | }, 550 | "node_modules/flat-cache": { 551 | "version": "6.1.5", 552 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.5.tgz", 553 | "integrity": "sha512-QR+2kN38f8nMfiIQ1LHYjuDEmZNZVjxuxY+HufbS3BW0EX01Q5OnH7iduOYRutmgiXb797HAKcXUeXrvRjjgSQ==", 554 | "license": "MIT", 555 | "dependencies": { 556 | "cacheable": "^1.8.7", 557 | "flatted": "^3.3.2", 558 | "hookified": "^1.6.0" 559 | } 560 | }, 561 | "node_modules/flatted": { 562 | "version": "3.3.2", 563 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", 564 | "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", 565 | "license": "ISC" 566 | }, 567 | "node_modules/glob-parent": { 568 | "version": "5.1.2", 569 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 570 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 571 | "license": "ISC", 572 | "dependencies": { 573 | "is-glob": "^4.0.1" 574 | }, 575 | "engines": { 576 | "node": ">= 6" 577 | } 578 | }, 579 | "node_modules/global-modules": { 580 | "version": "2.0.0", 581 | "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", 582 | "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", 583 | "license": "MIT", 584 | "dependencies": { 585 | "global-prefix": "^3.0.0" 586 | }, 587 | "engines": { 588 | "node": ">=6" 589 | } 590 | }, 591 | "node_modules/global-prefix": { 592 | "version": "3.0.0", 593 | "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", 594 | "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", 595 | "license": "MIT", 596 | "dependencies": { 597 | "ini": "^1.3.5", 598 | "kind-of": "^6.0.2", 599 | "which": "^1.3.1" 600 | }, 601 | "engines": { 602 | "node": ">=6" 603 | } 604 | }, 605 | "node_modules/globby": { 606 | "version": "11.1.0", 607 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", 608 | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", 609 | "license": "MIT", 610 | "dependencies": { 611 | "array-union": "^2.1.0", 612 | "dir-glob": "^3.0.1", 613 | "fast-glob": "^3.2.9", 614 | "ignore": "^5.2.0", 615 | "merge2": "^1.4.1", 616 | "slash": "^3.0.0" 617 | }, 618 | "engines": { 619 | "node": ">=10" 620 | }, 621 | "funding": { 622 | "url": "https://github.com/sponsors/sindresorhus" 623 | } 624 | }, 625 | "node_modules/globby/node_modules/ignore": { 626 | "version": "5.3.2", 627 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 628 | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 629 | "license": "MIT", 630 | "engines": { 631 | "node": ">= 4" 632 | } 633 | }, 634 | "node_modules/globjoin": { 635 | "version": "0.1.4", 636 | "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", 637 | "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", 638 | "license": "MIT" 639 | }, 640 | "node_modules/has-flag": { 641 | "version": "4.0.0", 642 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 643 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 644 | "license": "MIT", 645 | "engines": { 646 | "node": ">=8" 647 | } 648 | }, 649 | "node_modules/hookified": { 650 | "version": "1.6.0", 651 | "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.6.0.tgz", 652 | "integrity": "sha512-se7cpwTA+iA/eY548Bu03JJqBiEZAqU2jnyKdj5B5qurtBg64CZGHTgqCv4Yh7NWu6FGI09W61MCq+NoPj9GXA==", 653 | "license": "MIT" 654 | }, 655 | "node_modules/html-tags": { 656 | "version": "3.3.1", 657 | "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", 658 | "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", 659 | "license": "MIT", 660 | "engines": { 661 | "node": ">=8" 662 | }, 663 | "funding": { 664 | "url": "https://github.com/sponsors/sindresorhus" 665 | } 666 | }, 667 | "node_modules/ieee754": { 668 | "version": "1.2.1", 669 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 670 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 671 | "funding": [ 672 | { 673 | "type": "github", 674 | "url": "https://github.com/sponsors/feross" 675 | }, 676 | { 677 | "type": "patreon", 678 | "url": "https://www.patreon.com/feross" 679 | }, 680 | { 681 | "type": "consulting", 682 | "url": "https://feross.org/support" 683 | } 684 | ], 685 | "license": "BSD-3-Clause" 686 | }, 687 | "node_modules/ignore": { 688 | "version": "7.0.3", 689 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", 690 | "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", 691 | "license": "MIT", 692 | "engines": { 693 | "node": ">= 4" 694 | } 695 | }, 696 | "node_modules/import-fresh": { 697 | "version": "3.3.0", 698 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 699 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 700 | "license": "MIT", 701 | "dependencies": { 702 | "parent-module": "^1.0.0", 703 | "resolve-from": "^4.0.0" 704 | }, 705 | "engines": { 706 | "node": ">=6" 707 | }, 708 | "funding": { 709 | "url": "https://github.com/sponsors/sindresorhus" 710 | } 711 | }, 712 | "node_modules/import-fresh/node_modules/resolve-from": { 713 | "version": "4.0.0", 714 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 715 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 716 | "license": "MIT", 717 | "engines": { 718 | "node": ">=4" 719 | } 720 | }, 721 | "node_modules/imurmurhash": { 722 | "version": "0.1.4", 723 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 724 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 725 | "license": "MIT", 726 | "engines": { 727 | "node": ">=0.8.19" 728 | } 729 | }, 730 | "node_modules/ini": { 731 | "version": "1.3.8", 732 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 733 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 734 | "license": "ISC" 735 | }, 736 | "node_modules/is-arrayish": { 737 | "version": "0.2.1", 738 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 739 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", 740 | "license": "MIT" 741 | }, 742 | "node_modules/is-extglob": { 743 | "version": "2.1.1", 744 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 745 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 746 | "license": "MIT", 747 | "engines": { 748 | "node": ">=0.10.0" 749 | } 750 | }, 751 | "node_modules/is-fullwidth-code-point": { 752 | "version": "3.0.0", 753 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 754 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 755 | "license": "MIT", 756 | "engines": { 757 | "node": ">=8" 758 | } 759 | }, 760 | "node_modules/is-glob": { 761 | "version": "4.0.3", 762 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 763 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 764 | "license": "MIT", 765 | "dependencies": { 766 | "is-extglob": "^2.1.1" 767 | }, 768 | "engines": { 769 | "node": ">=0.10.0" 770 | } 771 | }, 772 | "node_modules/is-number": { 773 | "version": "7.0.0", 774 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 775 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 776 | "license": "MIT", 777 | "engines": { 778 | "node": ">=0.12.0" 779 | } 780 | }, 781 | "node_modules/is-plain-object": { 782 | "version": "5.0.0", 783 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 784 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 785 | "license": "MIT", 786 | "engines": { 787 | "node": ">=0.10.0" 788 | } 789 | }, 790 | "node_modules/isexe": { 791 | "version": "2.0.0", 792 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 793 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 794 | "license": "ISC" 795 | }, 796 | "node_modules/js-tokens": { 797 | "version": "4.0.0", 798 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 799 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 800 | "license": "MIT" 801 | }, 802 | "node_modules/js-yaml": { 803 | "version": "4.1.0", 804 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 805 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 806 | "license": "MIT", 807 | "dependencies": { 808 | "argparse": "^2.0.1" 809 | }, 810 | "bin": { 811 | "js-yaml": "bin/js-yaml.js" 812 | } 813 | }, 814 | "node_modules/json-parse-even-better-errors": { 815 | "version": "2.3.1", 816 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 817 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 818 | "license": "MIT" 819 | }, 820 | "node_modules/json-schema-traverse": { 821 | "version": "1.0.0", 822 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 823 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 824 | "license": "MIT" 825 | }, 826 | "node_modules/keyv": { 827 | "version": "5.2.3", 828 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.2.3.tgz", 829 | "integrity": "sha512-AGKecUfzrowabUv0bH1RIR5Vf7w+l4S3xtQAypKaUpTdIR1EbrAcTxHCrpo9Q+IWeUlFE2palRtgIQcgm+PQJw==", 830 | "license": "MIT", 831 | "dependencies": { 832 | "@keyv/serialize": "^1.0.2" 833 | } 834 | }, 835 | "node_modules/kind-of": { 836 | "version": "6.0.3", 837 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 838 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 839 | "license": "MIT", 840 | "engines": { 841 | "node": ">=0.10.0" 842 | } 843 | }, 844 | "node_modules/known-css-properties": { 845 | "version": "0.35.0", 846 | "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", 847 | "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", 848 | "license": "MIT" 849 | }, 850 | "node_modules/lines-and-columns": { 851 | "version": "1.2.4", 852 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 853 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 854 | "license": "MIT" 855 | }, 856 | "node_modules/lodash.truncate": { 857 | "version": "4.4.2", 858 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", 859 | "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", 860 | "license": "MIT" 861 | }, 862 | "node_modules/mathml-tag-names": { 863 | "version": "2.1.3", 864 | "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", 865 | "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", 866 | "license": "MIT", 867 | "funding": { 868 | "type": "github", 869 | "url": "https://github.com/sponsors/wooorm" 870 | } 871 | }, 872 | "node_modules/mdn-data": { 873 | "version": "2.12.2", 874 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", 875 | "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", 876 | "license": "CC0-1.0" 877 | }, 878 | "node_modules/meow": { 879 | "version": "13.2.0", 880 | "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", 881 | "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", 882 | "license": "MIT", 883 | "engines": { 884 | "node": ">=18" 885 | }, 886 | "funding": { 887 | "url": "https://github.com/sponsors/sindresorhus" 888 | } 889 | }, 890 | "node_modules/merge2": { 891 | "version": "1.4.1", 892 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 893 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 894 | "license": "MIT", 895 | "engines": { 896 | "node": ">= 8" 897 | } 898 | }, 899 | "node_modules/micromatch": { 900 | "version": "4.0.8", 901 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 902 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 903 | "license": "MIT", 904 | "dependencies": { 905 | "braces": "^3.0.3", 906 | "picomatch": "^2.3.1" 907 | }, 908 | "engines": { 909 | "node": ">=8.6" 910 | } 911 | }, 912 | "node_modules/ms": { 913 | "version": "2.1.3", 914 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 915 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 916 | "license": "MIT" 917 | }, 918 | "node_modules/nanoid": { 919 | "version": "3.3.8", 920 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", 921 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", 922 | "funding": [ 923 | { 924 | "type": "github", 925 | "url": "https://github.com/sponsors/ai" 926 | } 927 | ], 928 | "license": "MIT", 929 | "bin": { 930 | "nanoid": "bin/nanoid.cjs" 931 | }, 932 | "engines": { 933 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 934 | } 935 | }, 936 | "node_modules/normalize-path": { 937 | "version": "3.0.0", 938 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 939 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 940 | "license": "MIT", 941 | "engines": { 942 | "node": ">=0.10.0" 943 | } 944 | }, 945 | "node_modules/parent-module": { 946 | "version": "1.0.1", 947 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 948 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 949 | "license": "MIT", 950 | "dependencies": { 951 | "callsites": "^3.0.0" 952 | }, 953 | "engines": { 954 | "node": ">=6" 955 | } 956 | }, 957 | "node_modules/parse-json": { 958 | "version": "5.2.0", 959 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 960 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 961 | "license": "MIT", 962 | "dependencies": { 963 | "@babel/code-frame": "^7.0.0", 964 | "error-ex": "^1.3.1", 965 | "json-parse-even-better-errors": "^2.3.0", 966 | "lines-and-columns": "^1.1.6" 967 | }, 968 | "engines": { 969 | "node": ">=8" 970 | }, 971 | "funding": { 972 | "url": "https://github.com/sponsors/sindresorhus" 973 | } 974 | }, 975 | "node_modules/path-type": { 976 | "version": "4.0.0", 977 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 978 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 979 | "license": "MIT", 980 | "engines": { 981 | "node": ">=8" 982 | } 983 | }, 984 | "node_modules/picocolors": { 985 | "version": "1.1.1", 986 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 987 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 988 | "license": "ISC" 989 | }, 990 | "node_modules/picomatch": { 991 | "version": "2.3.1", 992 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 993 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 994 | "license": "MIT", 995 | "engines": { 996 | "node": ">=8.6" 997 | }, 998 | "funding": { 999 | "url": "https://github.com/sponsors/jonschlinkert" 1000 | } 1001 | }, 1002 | "node_modules/postcss": { 1003 | "version": "8.5.1", 1004 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", 1005 | "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", 1006 | "funding": [ 1007 | { 1008 | "type": "opencollective", 1009 | "url": "https://opencollective.com/postcss/" 1010 | }, 1011 | { 1012 | "type": "tidelift", 1013 | "url": "https://tidelift.com/funding/github/npm/postcss" 1014 | }, 1015 | { 1016 | "type": "github", 1017 | "url": "https://github.com/sponsors/ai" 1018 | } 1019 | ], 1020 | "license": "MIT", 1021 | "dependencies": { 1022 | "nanoid": "^3.3.8", 1023 | "picocolors": "^1.1.1", 1024 | "source-map-js": "^1.2.1" 1025 | }, 1026 | "engines": { 1027 | "node": "^10 || ^12 || >=14" 1028 | } 1029 | }, 1030 | "node_modules/postcss-media-query-parser": { 1031 | "version": "0.2.3", 1032 | "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", 1033 | "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", 1034 | "license": "MIT" 1035 | }, 1036 | "node_modules/postcss-resolve-nested-selector": { 1037 | "version": "0.1.6", 1038 | "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", 1039 | "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", 1040 | "license": "MIT" 1041 | }, 1042 | "node_modules/postcss-safe-parser": { 1043 | "version": "7.0.1", 1044 | "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", 1045 | "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", 1046 | "funding": [ 1047 | { 1048 | "type": "opencollective", 1049 | "url": "https://opencollective.com/postcss/" 1050 | }, 1051 | { 1052 | "type": "tidelift", 1053 | "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" 1054 | }, 1055 | { 1056 | "type": "github", 1057 | "url": "https://github.com/sponsors/ai" 1058 | } 1059 | ], 1060 | "license": "MIT", 1061 | "engines": { 1062 | "node": ">=18.0" 1063 | }, 1064 | "peerDependencies": { 1065 | "postcss": "^8.4.31" 1066 | } 1067 | }, 1068 | "node_modules/postcss-scss": { 1069 | "version": "4.0.9", 1070 | "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", 1071 | "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", 1072 | "funding": [ 1073 | { 1074 | "type": "opencollective", 1075 | "url": "https://opencollective.com/postcss/" 1076 | }, 1077 | { 1078 | "type": "tidelift", 1079 | "url": "https://tidelift.com/funding/github/npm/postcss-scss" 1080 | }, 1081 | { 1082 | "type": "github", 1083 | "url": "https://github.com/sponsors/ai" 1084 | } 1085 | ], 1086 | "license": "MIT", 1087 | "engines": { 1088 | "node": ">=12.0" 1089 | }, 1090 | "peerDependencies": { 1091 | "postcss": "^8.4.29" 1092 | } 1093 | }, 1094 | "node_modules/postcss-selector-parser": { 1095 | "version": "6.1.2", 1096 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 1097 | "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 1098 | "license": "MIT", 1099 | "dependencies": { 1100 | "cssesc": "^3.0.0", 1101 | "util-deprecate": "^1.0.2" 1102 | }, 1103 | "engines": { 1104 | "node": ">=4" 1105 | } 1106 | }, 1107 | "node_modules/postcss-value-parser": { 1108 | "version": "4.2.0", 1109 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 1110 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 1111 | "license": "MIT" 1112 | }, 1113 | "node_modules/queue-microtask": { 1114 | "version": "1.2.3", 1115 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1116 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1117 | "funding": [ 1118 | { 1119 | "type": "github", 1120 | "url": "https://github.com/sponsors/feross" 1121 | }, 1122 | { 1123 | "type": "patreon", 1124 | "url": "https://www.patreon.com/feross" 1125 | }, 1126 | { 1127 | "type": "consulting", 1128 | "url": "https://feross.org/support" 1129 | } 1130 | ], 1131 | "license": "MIT" 1132 | }, 1133 | "node_modules/require-from-string": { 1134 | "version": "2.0.2", 1135 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 1136 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 1137 | "license": "MIT", 1138 | "engines": { 1139 | "node": ">=0.10.0" 1140 | } 1141 | }, 1142 | "node_modules/resolve-from": { 1143 | "version": "5.0.0", 1144 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 1145 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 1146 | "license": "MIT", 1147 | "engines": { 1148 | "node": ">=8" 1149 | } 1150 | }, 1151 | "node_modules/reusify": { 1152 | "version": "1.0.4", 1153 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1154 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1155 | "license": "MIT", 1156 | "engines": { 1157 | "iojs": ">=1.0.0", 1158 | "node": ">=0.10.0" 1159 | } 1160 | }, 1161 | "node_modules/run-parallel": { 1162 | "version": "1.2.0", 1163 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1164 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1165 | "funding": [ 1166 | { 1167 | "type": "github", 1168 | "url": "https://github.com/sponsors/feross" 1169 | }, 1170 | { 1171 | "type": "patreon", 1172 | "url": "https://www.patreon.com/feross" 1173 | }, 1174 | { 1175 | "type": "consulting", 1176 | "url": "https://feross.org/support" 1177 | } 1178 | ], 1179 | "license": "MIT", 1180 | "dependencies": { 1181 | "queue-microtask": "^1.2.2" 1182 | } 1183 | }, 1184 | "node_modules/signal-exit": { 1185 | "version": "4.1.0", 1186 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 1187 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 1188 | "license": "ISC", 1189 | "engines": { 1190 | "node": ">=14" 1191 | }, 1192 | "funding": { 1193 | "url": "https://github.com/sponsors/isaacs" 1194 | } 1195 | }, 1196 | "node_modules/slash": { 1197 | "version": "3.0.0", 1198 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1199 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1200 | "license": "MIT", 1201 | "engines": { 1202 | "node": ">=8" 1203 | } 1204 | }, 1205 | "node_modules/slice-ansi": { 1206 | "version": "4.0.0", 1207 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", 1208 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", 1209 | "license": "MIT", 1210 | "dependencies": { 1211 | "ansi-styles": "^4.0.0", 1212 | "astral-regex": "^2.0.0", 1213 | "is-fullwidth-code-point": "^3.0.0" 1214 | }, 1215 | "engines": { 1216 | "node": ">=10" 1217 | }, 1218 | "funding": { 1219 | "url": "https://github.com/chalk/slice-ansi?sponsor=1" 1220 | } 1221 | }, 1222 | "node_modules/source-map-js": { 1223 | "version": "1.2.1", 1224 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1225 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1226 | "license": "BSD-3-Clause", 1227 | "engines": { 1228 | "node": ">=0.10.0" 1229 | } 1230 | }, 1231 | "node_modules/string-width": { 1232 | "version": "4.2.3", 1233 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1234 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1235 | "license": "MIT", 1236 | "dependencies": { 1237 | "emoji-regex": "^8.0.0", 1238 | "is-fullwidth-code-point": "^3.0.0", 1239 | "strip-ansi": "^6.0.1" 1240 | }, 1241 | "engines": { 1242 | "node": ">=8" 1243 | } 1244 | }, 1245 | "node_modules/strip-ansi": { 1246 | "version": "6.0.1", 1247 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1248 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1249 | "license": "MIT", 1250 | "dependencies": { 1251 | "ansi-regex": "^5.0.1" 1252 | }, 1253 | "engines": { 1254 | "node": ">=8" 1255 | } 1256 | }, 1257 | "node_modules/style-search": { 1258 | "version": "0.1.0", 1259 | "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", 1260 | "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", 1261 | "license": "ISC" 1262 | }, 1263 | "node_modules/stylelint": { 1264 | "version": "16.13.2", 1265 | "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.2.tgz", 1266 | "integrity": "sha512-wDlgh0mRO9RtSa3TdidqHd0nOG8MmUyVKl+dxA6C1j8aZRzpNeEgdhFmU5y4sZx4Fc6r46p0fI7p1vR5O2DZqA==", 1267 | "funding": [ 1268 | { 1269 | "type": "opencollective", 1270 | "url": "https://opencollective.com/stylelint" 1271 | }, 1272 | { 1273 | "type": "github", 1274 | "url": "https://github.com/sponsors/stylelint" 1275 | } 1276 | ], 1277 | "license": "MIT", 1278 | "dependencies": { 1279 | "@csstools/css-parser-algorithms": "^3.0.4", 1280 | "@csstools/css-tokenizer": "^3.0.3", 1281 | "@csstools/media-query-list-parser": "^4.0.2", 1282 | "@csstools/selector-specificity": "^5.0.0", 1283 | "@dual-bundle/import-meta-resolve": "^4.1.0", 1284 | "balanced-match": "^2.0.0", 1285 | "colord": "^2.9.3", 1286 | "cosmiconfig": "^9.0.0", 1287 | "css-functions-list": "^3.2.3", 1288 | "css-tree": "^3.1.0", 1289 | "debug": "^4.3.7", 1290 | "fast-glob": "^3.3.3", 1291 | "fastest-levenshtein": "^1.0.16", 1292 | "file-entry-cache": "^10.0.5", 1293 | "global-modules": "^2.0.0", 1294 | "globby": "^11.1.0", 1295 | "globjoin": "^0.1.4", 1296 | "html-tags": "^3.3.1", 1297 | "ignore": "^7.0.1", 1298 | "imurmurhash": "^0.1.4", 1299 | "is-plain-object": "^5.0.0", 1300 | "known-css-properties": "^0.35.0", 1301 | "mathml-tag-names": "^2.1.3", 1302 | "meow": "^13.2.0", 1303 | "micromatch": "^4.0.8", 1304 | "normalize-path": "^3.0.0", 1305 | "picocolors": "^1.1.1", 1306 | "postcss": "^8.4.49", 1307 | "postcss-resolve-nested-selector": "^0.1.6", 1308 | "postcss-safe-parser": "^7.0.1", 1309 | "postcss-selector-parser": "^7.0.0", 1310 | "postcss-value-parser": "^4.2.0", 1311 | "resolve-from": "^5.0.0", 1312 | "string-width": "^4.2.3", 1313 | "supports-hyperlinks": "^3.1.0", 1314 | "svg-tags": "^1.0.0", 1315 | "table": "^6.9.0", 1316 | "write-file-atomic": "^5.0.1" 1317 | }, 1318 | "bin": { 1319 | "stylelint": "bin/stylelint.mjs" 1320 | }, 1321 | "engines": { 1322 | "node": ">=18.12.0" 1323 | } 1324 | }, 1325 | "node_modules/stylelint-scss": { 1326 | "version": "6.10.0", 1327 | "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.10.0.tgz", 1328 | "integrity": "sha512-y03if6Qw9xBMoVaf7tzp5BbnYhYvudIKzURkhSHzcHG0bW0fAYvQpTUVJOe7DyhHaxeThBil4ObEMvGbV7+M+w==", 1329 | "license": "MIT", 1330 | "dependencies": { 1331 | "css-tree": "^3.0.1", 1332 | "is-plain-object": "^5.0.0", 1333 | "known-css-properties": "^0.35.0", 1334 | "mdn-data": "^2.12.2", 1335 | "postcss-media-query-parser": "^0.2.3", 1336 | "postcss-resolve-nested-selector": "^0.1.6", 1337 | "postcss-selector-parser": "^7.0.0", 1338 | "postcss-value-parser": "^4.2.0" 1339 | }, 1340 | "engines": { 1341 | "node": ">=18.12.0" 1342 | }, 1343 | "peerDependencies": { 1344 | "stylelint": "^16.0.2" 1345 | } 1346 | }, 1347 | "node_modules/stylelint-scss/node_modules/postcss-selector-parser": { 1348 | "version": "7.0.0", 1349 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", 1350 | "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", 1351 | "license": "MIT", 1352 | "dependencies": { 1353 | "cssesc": "^3.0.0", 1354 | "util-deprecate": "^1.0.2" 1355 | }, 1356 | "engines": { 1357 | "node": ">=4" 1358 | } 1359 | }, 1360 | "node_modules/stylelint/node_modules/@csstools/media-query-list-parser": { 1361 | "version": "4.0.2", 1362 | "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", 1363 | "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", 1364 | "funding": [ 1365 | { 1366 | "type": "github", 1367 | "url": "https://github.com/sponsors/csstools" 1368 | }, 1369 | { 1370 | "type": "opencollective", 1371 | "url": "https://opencollective.com/csstools" 1372 | } 1373 | ], 1374 | "license": "MIT", 1375 | "engines": { 1376 | "node": ">=18" 1377 | }, 1378 | "peerDependencies": { 1379 | "@csstools/css-parser-algorithms": "^3.0.4", 1380 | "@csstools/css-tokenizer": "^3.0.3" 1381 | } 1382 | }, 1383 | "node_modules/stylelint/node_modules/@csstools/selector-specificity": { 1384 | "version": "5.0.0", 1385 | "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", 1386 | "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", 1387 | "funding": [ 1388 | { 1389 | "type": "github", 1390 | "url": "https://github.com/sponsors/csstools" 1391 | }, 1392 | { 1393 | "type": "opencollective", 1394 | "url": "https://opencollective.com/csstools" 1395 | } 1396 | ], 1397 | "license": "MIT-0", 1398 | "engines": { 1399 | "node": ">=18" 1400 | }, 1401 | "peerDependencies": { 1402 | "postcss-selector-parser": "^7.0.0" 1403 | } 1404 | }, 1405 | "node_modules/stylelint/node_modules/postcss-selector-parser": { 1406 | "version": "7.0.0", 1407 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", 1408 | "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", 1409 | "license": "MIT", 1410 | "dependencies": { 1411 | "cssesc": "^3.0.0", 1412 | "util-deprecate": "^1.0.2" 1413 | }, 1414 | "engines": { 1415 | "node": ">=4" 1416 | } 1417 | }, 1418 | "node_modules/supports-color": { 1419 | "version": "7.2.0", 1420 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1421 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1422 | "license": "MIT", 1423 | "dependencies": { 1424 | "has-flag": "^4.0.0" 1425 | }, 1426 | "engines": { 1427 | "node": ">=8" 1428 | } 1429 | }, 1430 | "node_modules/supports-hyperlinks": { 1431 | "version": "3.1.0", 1432 | "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz", 1433 | "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==", 1434 | "license": "MIT", 1435 | "dependencies": { 1436 | "has-flag": "^4.0.0", 1437 | "supports-color": "^7.0.0" 1438 | }, 1439 | "engines": { 1440 | "node": ">=14.18" 1441 | }, 1442 | "funding": { 1443 | "url": "https://github.com/sponsors/sindresorhus" 1444 | } 1445 | }, 1446 | "node_modules/svg-tags": { 1447 | "version": "1.0.0", 1448 | "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", 1449 | "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==" 1450 | }, 1451 | "node_modules/table": { 1452 | "version": "6.9.0", 1453 | "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", 1454 | "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", 1455 | "license": "BSD-3-Clause", 1456 | "dependencies": { 1457 | "ajv": "^8.0.1", 1458 | "lodash.truncate": "^4.4.2", 1459 | "slice-ansi": "^4.0.0", 1460 | "string-width": "^4.2.3", 1461 | "strip-ansi": "^6.0.1" 1462 | }, 1463 | "engines": { 1464 | "node": ">=10.0.0" 1465 | } 1466 | }, 1467 | "node_modules/to-regex-range": { 1468 | "version": "5.0.1", 1469 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1470 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1471 | "license": "MIT", 1472 | "dependencies": { 1473 | "is-number": "^7.0.0" 1474 | }, 1475 | "engines": { 1476 | "node": ">=8.0" 1477 | } 1478 | }, 1479 | "node_modules/util-deprecate": { 1480 | "version": "1.0.2", 1481 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1482 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1483 | "license": "MIT" 1484 | }, 1485 | "node_modules/which": { 1486 | "version": "1.3.1", 1487 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1488 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1489 | "license": "ISC", 1490 | "dependencies": { 1491 | "isexe": "^2.0.0" 1492 | }, 1493 | "bin": { 1494 | "which": "bin/which" 1495 | } 1496 | }, 1497 | "node_modules/write-file-atomic": { 1498 | "version": "5.0.1", 1499 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", 1500 | "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", 1501 | "license": "ISC", 1502 | "dependencies": { 1503 | "imurmurhash": "^0.1.4", 1504 | "signal-exit": "^4.0.1" 1505 | }, 1506 | "engines": { 1507 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 1508 | } 1509 | } 1510 | } 1511 | } 1512 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-config-sass-guidelines", 3 | "version": "12.1.0", 4 | "description": "Sharable stylelint config based on https://sass-guidelin.es/", 5 | "keywords": [ 6 | "stylelint", 7 | "stylelint-config", 8 | "stylelint-scss", 9 | "scss", 10 | "sass", 11 | "guidelines", 12 | "lint", 13 | "linter" 14 | ], 15 | "author": "Brett Jankord", 16 | "license": "MIT", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/bjankord/stylelint-config-sass-guidelines.git" 20 | }, 21 | "homepage": "https://github.com/bjankord/stylelint-config-sass-guidelines#readme", 22 | "bugs": { 23 | "url": "https://github.com/bjankord/stylelint-config-sass-guidelines/issues" 24 | }, 25 | "engines": { 26 | "node": ">=18.12.0" 27 | }, 28 | "main": "index.js", 29 | "files": [ 30 | "index.js" 31 | ], 32 | "dependencies": { 33 | "@stylistic/stylelint-plugin": "^3.0.1", 34 | "postcss-scss": "^4.0.9", 35 | "stylelint-scss": "^6.2.1" 36 | }, 37 | "peerDependencies": { 38 | "postcss": "^8.4.21", 39 | "stylelint": "^16.1.0" 40 | }, 41 | "devDependencies": { 42 | "postcss": "^8.4.21", 43 | "stylelint": "^16.1.0" 44 | }, 45 | "scripts": { 46 | "release:major": "npm test && npm version major -m \"Released version %s\" && npm publish && git push --follow-tags", 47 | "release:minor": "npm test && npm version minor -m \"Released version %s\" && npm publish && git push --follow-tags", 48 | "release:patch": "npm test && npm version patch -m \"Released version %s\" && npm publish && git push --follow-tags", 49 | "test": "node --test" 50 | } 51 | } 52 | --------------------------------------------------------------------------------