├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── code-scanning.yml │ ├── lint.yml │ └── test.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .remarkrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __tests__ ├── index.test.mjs ├── invalid.scss └── valid.scss ├── eslint.config.mjs ├── index.js ├── package-lock.json └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: monthly 7 | - package-ecosystem: 'npm' 8 | directory: '/' 9 | schedule: 10 | interval: monthly 11 | versioning-strategy: increase 12 | -------------------------------------------------------------------------------- /.github/workflows/code-scanning.yml: -------------------------------------------------------------------------------- 1 | name: 'Code Scanning' 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - '!dependabot/**' 8 | pull_request: 9 | branches: 10 | - main 11 | - '!dependabot/**' 12 | schedule: 13 | - cron: '0 7 * * 1' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | runs-on: ubuntu-latest 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v4 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v3 33 | with: 34 | languages: 'javascript' 35 | queries: +security-and-quality 36 | 37 | - name: Autobuild 38 | uses: github/codeql-action/autobuild@v3 39 | 40 | - name: Perform CodeQL Analysis 41 | uses: github/codeql-action/analyze@v3 42 | with: 43 | category: '/language:javascript' 44 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - '!dependabot/**' 8 | pull_request: 9 | workflow_dispatch: 10 | 11 | env: 12 | FORCE_COLOR: 2 13 | NODE: 20 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | lint: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Clone repository 24 | uses: actions/checkout@v4 25 | with: 26 | persist-credentials: false 27 | 28 | - name: Set up Node.js 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: '${{ env.NODE }}' 32 | cache: npm 33 | 34 | - name: Install npm dependencies 35 | run: npm ci 36 | 37 | - name: Lint 38 | run: npm run lint 39 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - '!dependabot/**' 8 | pull_request: 9 | workflow_dispatch: 10 | 11 | env: 12 | FORCE_COLOR: 2 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | run: 19 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | node: [20] 26 | os: [ubuntu-latest, windows-latest, macos-latest] 27 | 28 | steps: 29 | - name: Clone repository 30 | uses: actions/checkout@v4 31 | with: 32 | persist-credentials: false 33 | 34 | - name: Set up Node.js 35 | uses: actions/setup-node@v4 36 | with: 37 | node-version: ${{ matrix.node }} 38 | cache: npm 39 | 40 | - name: Install npm dependencies 41 | run: npm ci 42 | 43 | - name: Run tests 44 | run: npm test 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | lockfile-version=2 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /__tests__/*.scss 2 | /package.json 3 | /package-lock.json 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | "@stylelint/prettier-config" 2 | -------------------------------------------------------------------------------- /.remarkrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@stylelint/remark-preset"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 15.0.1 2 | 3 | - Fixed: change minimum supported Node.js version to `20`. 4 | 5 | # 15.0.0 6 | 7 | - Changed: updated to [`stylelint-config-recommended-scss@15.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v15.0.0). 8 | - Changed: updated to [`stylelint-config-standard@38.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/38.0.0) 9 | - Removed: `stylelint` less than `16.18.0` from peer dependencies. 10 | - Removed: Node.js less than `22` support. 11 | - Fixed: `length-zero-no-unit` allow mixin/function argument default values with unit (#221). 12 | 13 | # 14.0.0 14 | 15 | - Changed: updated to [`stylelint-config-recommended-scss@14.1.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v14.1.0). 16 | - Removed: `stylelint` less than `16.11.0` from peer dependencies. 17 | 18 | # 13.1.0 19 | 20 | - Changed: `scss/dollar-variable-colon-space-after` from `always` to `always-single-line` to be compatible with the default formatting of Prettier. 21 | 22 | # 13.0.0 23 | 24 | - Changed: updated to [`stylelint-config-standard@36.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/36.0.0) 25 | - Removed: `stylelint` less than `16.1.0` from peer dependencies. 26 | 27 | # 12.0.0 28 | 29 | - Changed: updated to [`stylelint-config-recommended-scss@14.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v14.0.0). 30 | - Changed: updated to [`stylelint-config-standard@35.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/35.0.0) 31 | - Removed: `stylelint` less than `16.0.2` from peer dependencies. 32 | - Removed: Node.js less than `18.12.0` support. 33 | 34 | # 11.1.0 35 | 36 | - Changed: updated to [`stylelint-config-recommended-scss@13.1.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v13.1.0). 37 | 38 | # 11.0.0 39 | 40 | - Changed: updated to [`stylelint-config-recommended-scss@13.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v13.0.0). 41 | - Changed: updated to [`stylelint-config-standard@34.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/34.0.0) 42 | - Removed: `stylelint` less than `15.10.0` from peer dependencies. 43 | 44 | # 10.0.0 45 | 46 | - Changed: updated to [`stylelint-config-recommended-scss@12.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v12.0.0). 47 | 48 | # 9.0.0 49 | 50 | - Changed: updated to [`stylelint-config-recommended-scss@11.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v11.0.0). 51 | - Changed: updated to [`stylelint-config-standard@33.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/33.0.0) 52 | - Removed: `stylelint` less than `15.5.0` from peer dependencies. 53 | 54 | # 8.0.0 55 | 56 | - Changed: updated to [`stylelint-config-recommended-scss@10.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v10.0.0). 57 | - Changed: updated to [`stylelint-config-standard@32.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/32.0.0) 58 | - Removed: `stylelint` less than `15.4.0` from peer dependencies. 59 | 60 | # 7.0.1 61 | 62 | - Fixed: remove deprecated rule `block-closing-brace-newline-after` (#68). 63 | 64 | # 7.0.0 65 | 66 | - Changed: updated to [`stylelint-config-recommended-scss@9.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v9.0.0). 67 | - Changed: updated to [`stylelint-config-standard@30.0.1`](https://github.com/stylelint/stylelint-config-standard/releases/tag/30.0.1) 68 | - Removed: `stylelint` less than `15.0.0` from peer dependencies. 69 | 70 | # 6.1.0 71 | 72 | - Added: `postcss` as an optional peer dependency. 73 | 74 | # 6.0.0 75 | 76 | - Changed: updated to [`stylelint-config-recommended-scss@8.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v8.0.0). 77 | - Changed: updated to [`stylelint-config-standard@29.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/29.0.0) 78 | - Removed: `stylelint` less than `14.14.0` from peer dependencies. 79 | 80 | # 5.0.0 81 | 82 | - Changed: updated to [`stylelint-config-recommended-scss@7.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v7.0.0). 83 | - Changed: updated to [`stylelint-config-standard@26.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/26.0.0) 84 | - Removed: `stylelint` less than `14.9.0` from peer dependencies. 85 | 86 | # 4.0.0 87 | 88 | - Changed: updated to [`stylelint-config-recommended-scss@6.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/v6.0.0). 89 | - Changed: updated to [`stylelint-config-standard@25.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/25.0.0) 90 | - Removed: `stylelint` less than `14.4.0` from peer dependencies. 91 | 92 | # 3.0.0 93 | 94 | - Changed: updated to [`stylelint-config-standard@24.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/24.0.0). 95 | - Fixed: allow private Sass mixins, placeholders and functions when using kebab case. 96 | 97 | # 2.0.1 98 | 99 | - Fixed: allow private Sass variables when using kebab case. 100 | 101 | # 2.0.0 102 | 103 | This release adds over a dozen new rules. 104 | 105 | If needed, you can [extend the config](README.md#extending-the-config) to turn off any of the new rules. 106 | 107 | - Removed: `stylelint` less than `14.0.0` from peer dependencies. 108 | - Changed: updated to [`stylelint-config-recommended-scss@5.0.0`](https://github.com/stylelint-scss/stylelint-config-recommended-scss/releases/tag/5.0.0). 109 | - Changed: updated to [`stylelint-config-standard@23.0.0`](https://github.com/stylelint/stylelint-config-standard/releases/tag/23.0.0). 110 | - Added: `scss/at-else-closing-brace-newline-after` rule. 111 | - Added: `scss/at-else-closing-brace-space-after` rule. 112 | - Added: `scss/at-else-empty-line-before` rule. 113 | - Added: `scss/at-else-if-parentheses-space-before` rule. 114 | - Added: `scss/at-function-parentheses-space-before` rule. 115 | - Added: `scss/at-function-pattern` rule. 116 | - Added: `scss/at-if-closing-brace-newline-after` rule. 117 | - Added: `scss/at-if-closing-brace-space-after` rule. 118 | - Added: `scss/at-mixin-argumentless-call-parentheses` rule. 119 | - Added: `scss/at-mixin-parentheses-space-before` rule. 120 | - Added: `scss/at-mixin-pattern` rule. 121 | - Added: `scss/at-rule-conditional-no-parentheses` rule. 122 | - Added: `scss/dollar-variable-colon-space-after` rule. 123 | - Added: `scss/dollar-variable-colon-space-before` rule. 124 | - Added: `scss/dollar-variable-empty-line-before` rule. 125 | - Added: `scss/dollar-variable-pattern` rule. 126 | - Added: `scss/double-slash-comment-empty-line-before` rule. 127 | - Added: `scss/double-slash-comment-whitespace-inside` rule. 128 | - Added: `scss/percent-placeholder-pattern` rule. 129 | 130 | # 1.1.0 131 | 132 | - Updated `peerDependencies` to include `stylelint@10` 133 | 134 | # 1.0.0 135 | 136 | - Initial release 137 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Present stylelint-scss authors 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-standard-scss 2 | 3 | [![npm version](https://img.shields.io/npm/v/stylelint-config-standard-scss?logo=npm&logoColor=fff)](https://www.npmjs.com/package/stylelint-config-standard-scss) 4 | [![Build Status](https://img.shields.io/github/actions/workflow/status/stylelint-scss/stylelint-config-standard-scss/test.yml?branch=main&label=tests&logo=github)](https://github.com/stylelint-scss/stylelint-config-standard-scss/actions/workflows/test.yml?query=workflow%3ATests) 5 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen)](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) 6 | [![Downloads per month](https://img.shields.io/npm/dm/stylelint-config-standard-scss)](https://npmcharts.com/compare/stylelint-config-standard-scss) 7 | 8 | > The standard shareable SCSS config for Stylelint. 9 | 10 | This config: 11 | 12 | - extends the [`stylelint-config-standard` shared config](https://github.com/stylelint/stylelint-config-standard) and configures its rules for SCSS 13 | - extends the [`stylelint-config-recommended-scss` shared config](https://github.com/stylelint-scss/stylelint-config-recommended-scss) 14 | 15 | To see the rules that this config uses, please read the [config itself](/index.js). 16 | 17 | ## Installation 18 | 19 | ```shell 20 | npm install --save-dev stylelint-config-standard-scss 21 | ``` 22 | 23 | ## Usage 24 | 25 | Set your `stylelint` config to: 26 | 27 | ```json 28 | { 29 | "extends": "stylelint-config-standard-scss" 30 | } 31 | ``` 32 | 33 | ### Extending the config 34 | 35 | Simply add a `"rules"` key to your config, then add your overrides and additions there. 36 | 37 | For example, to turn off the `scss/dollar-variable-pattern` rule: 38 | 39 | ```json 40 | { 41 | "extends": "stylelint-config-standard-scss", 42 | "rules": { 43 | "scss/dollar-variable-pattern": null 44 | } 45 | } 46 | ``` 47 | 48 | ## [Changelog](CHANGELOG.md) 49 | 50 | ## [License](LICENSE) 51 | -------------------------------------------------------------------------------- /__tests__/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, it } from 'node:test'; // eslint-disable-line n/no-unsupported-features/node-builtins 2 | import assert from 'node:assert/strict'; 3 | import { readFileSync } from 'node:fs'; 4 | 5 | import stylelint from 'stylelint'; 6 | 7 | import config from '../index.js'; 8 | 9 | const validScss = readFileSync('./__tests__/valid.scss', 'utf-8'); 10 | const invalidScss = readFileSync('./__tests__/invalid.scss', 'utf-8'); 11 | 12 | describe('flags no warnings with valid scss', () => { 13 | let result; 14 | 15 | beforeEach(async () => { 16 | result = await stylelint.lint({ 17 | code: validScss, 18 | config, 19 | }); 20 | }); 21 | 22 | it('did not error', () => { 23 | assert.equal(result.errored, false); 24 | }); 25 | 26 | it('flags no warnings', () => { 27 | assert.equal(result.results[0].warnings.length, 0); 28 | }); 29 | }); 30 | 31 | describe('flags warnings with invalid scss', () => { 32 | let result; 33 | 34 | beforeEach(async () => { 35 | result = await stylelint.lint({ 36 | code: invalidScss, 37 | config, 38 | }); 39 | }); 40 | 41 | it('did error', () => { 42 | assert.equal(result.errored, true); 43 | }); 44 | 45 | it('flags one warning', () => { 46 | assert.equal(result.results[0].warnings.length, 1); 47 | }); 48 | 49 | it('correct warning text', () => { 50 | assert.equal(result.results[0].warnings[0].text, 'Expected variable to be kebab-case'); 51 | }); 52 | 53 | it('correct rule flagged', () => { 54 | assert.equal(result.results[0].warnings[0].rule, 'scss/dollar-variable-pattern'); 55 | }); 56 | 57 | it('correct severity flagged', () => { 58 | assert.equal(result.results[0].warnings[0].severity, 'error'); 59 | }); 60 | 61 | it('correct line number', () => { 62 | assert.equal(result.results[0].warnings[0].line, 1); 63 | }); 64 | 65 | it('correct column number', () => { 66 | assert.equal(result.results[0].warnings[0].column, 1); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /__tests__/invalid.scss: -------------------------------------------------------------------------------- 1 | $FOO: 1; 2 | -------------------------------------------------------------------------------- /__tests__/valid.scss: -------------------------------------------------------------------------------- 1 | @forward "something"; 2 | @use "base"; 3 | @use "sass:list"; 4 | @use "sass:map"; 5 | @use "sass:math"; 6 | @use "sass:meta"; 7 | @use "sass:string"; 8 | @import "something-else"; 9 | 10 | // Multi-line double-slash comment 11 | // comment 12 | 13 | @function remove-where($list, $condition) { 14 | $new-list: (); 15 | $separator: list.separator($list); 16 | 17 | @each $element in $list { 18 | @if not meta.call($condition, $element) { 19 | $new-list: list.append($new-list, $element, $separator: $separator); 20 | } 21 | } 22 | 23 | @return $new-list; 24 | } 25 | 26 | @function -private-function() { 27 | @return true; 28 | } 29 | 30 | @mixin corner-icon($name, $top-or-bottom, $left-or-right) { 31 | .icon-#{$name} { 32 | background-image: url("/icons/#{$name}.svg"); 33 | position: absolute; 34 | #{$top-or-bottom}: 0; 35 | #{$left-or-right}: 0; 36 | } 37 | } 38 | 39 | @mixin triangle($size, $color, $direction) { 40 | border-color: transparent; 41 | border-style: solid; 42 | border-width: math.div($size, 2); 43 | 44 | @if $direction == up { 45 | border-bottom-color: $color; 46 | } @else if $direction == right { 47 | border-left-color: $color; 48 | } @else if $direction == down { 49 | border-top-color: $color; 50 | } @else if $direction == left { 51 | border-right-color: $color; 52 | } @else { 53 | @error "Unknown direction #{$direction}."; 54 | } 55 | } 56 | 57 | @mixin theme($theme: DarkGray) { 58 | background: $theme; 59 | box-shadow: 0 0 1px rgb($theme / 25%); 60 | } 61 | 62 | @mixin -private-mixin() { 63 | border: 1px; 64 | } 65 | 66 | %message-shared { 67 | border: 1px solid #ccc; 68 | color: #333; 69 | } 70 | 71 | %-private-placeholder { 72 | border: 1px; 73 | } 74 | 75 | $-private-size: 10rem; 76 | $local-color: #333; 77 | $fonts: "Tahoma", "Helvetica Neue", "Helvetica", sans-serif; 78 | $theme-colors: ( 79 | "success": #28a745, 80 | "warning": #ffc107, 81 | ); 82 | 83 | :root { 84 | --brand-red: hsl(5deg 10% 40%); 85 | } 86 | 87 | .selector-1, 88 | .selector-3[type="text"] { 89 | background: linear-gradient(#fff, rgb(0 0 0 / 80%)); 90 | color: base.$primary-color; 91 | top: calc(100% - 2rem) !important; 92 | 93 | a { 94 | width: math.div(300px, 960px) * 100%; 95 | } 96 | } 97 | 98 | .selector-x { width: 10%; } 99 | .selector-y { width: 20%; } 100 | .selector-z { width: 30%; } 101 | 102 | .selector-a { 103 | @include theme; 104 | } 105 | 106 | .selector-b { 107 | @extend %message-shared; 108 | @include theme($theme: DarkRed); 109 | } 110 | 111 | /* Single-line comment */ 112 | 113 | @media (width >= 60em) { 114 | .selector { 115 | // Flush to parent comment 116 | @include corner-icon("mail", top, left); 117 | 118 | transform: translate(100%, 100%) scale(3); 119 | } 120 | } 121 | 122 | @media (orientation: portrait), projection and (color) { 123 | // Flush to parent double-slash comment 124 | .selector-i + .selector-ii { 125 | @include triangle(5px, black, right); 126 | 127 | background: hsl(20deg 25% 33%); 128 | 129 | .selector-j { 130 | @function contains-helvetica($string) { 131 | @return string.index($string, "Helvetica"); 132 | } 133 | 134 | font-family: remove-where($fonts, meta.get-function("contains-helvetica")); 135 | } 136 | } 137 | } 138 | 139 | // Multi-line double-slash comment 140 | // comment 141 | @media 142 | screen and (resolution >= 192dpi), 143 | screen and (resolution >= 2dppx) { 144 | .selector { 145 | background-image: 146 | repeating-linear-gradient( 147 | -45deg, 148 | transparent, 149 | #fff 25px, 150 | rgb(255 255 255 / 100%) 50px 151 | ); 152 | height: 10rem; 153 | } 154 | 155 | /* Flush nested single line comment */ 156 | .selector::after { 157 | background-color: map.get($theme-colors, "warning"); 158 | content: "→"; 159 | background-image: url("x.svg"); 160 | } 161 | } 162 | 163 | @keyframes fade-in { 164 | from { opacity: 0; } 165 | to { opacity: 1; } 166 | } 167 | 168 | $ratios: 169 | 5 4, 170 | 4 3, 171 | 3 2, 172 | 16 9; 173 | 174 | @mixin hardcode-total-height($base-height, $extra-height: 0px) { 175 | height: calc($base-height + $extra-height); 176 | } 177 | 178 | a { 179 | @include hardcode-total-height(10px); 180 | } 181 | 182 | @function add-numbers($number-a, $number-b: 0px) { 183 | @return calc($number-a + $number-b) 184 | } 185 | 186 | div { 187 | width: add-numbers(10px); 188 | } 189 | 190 | // issue #214 191 | .name { 192 | &-suffix { 193 | content: ''; 194 | } 195 | } 196 | 197 | // issue #184 198 | .arrow-button { 199 | // stylelint-disable-next-line no-duplicate-selectors 200 | & { 201 | @include utils.focus-visible; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import stylelintConfig from 'eslint-config-stylelint'; 2 | 3 | export default stylelintConfig; 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: ['stylelint-config-standard', 'stylelint-config-recommended-scss'], 5 | rules: { 6 | 'at-rule-empty-line-before': [ 7 | 'always', 8 | { 9 | except: ['blockless-after-blockless', 'first-nested'], 10 | ignore: ['after-comment'], 11 | ignoreAtRules: ['else'], 12 | }, 13 | ], 14 | 'import-notation': 'string', 15 | 'length-zero-no-unit': [ 16 | true, 17 | { 18 | ignore: ['custom-properties'], 19 | ignorePreludeOfAtRules: ['function', 'mixin'], 20 | }, 21 | ], 22 | 'scss/at-else-closing-brace-newline-after': 'always-last-in-chain', 23 | 'scss/at-else-closing-brace-space-after': 'always-intermediate', 24 | 'scss/at-else-empty-line-before': 'never', 25 | 'scss/at-else-if-parentheses-space-before': 'always', 26 | 'scss/at-function-parentheses-space-before': 'never', 27 | 'scss/at-function-pattern': [ 28 | '^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$', 29 | { 30 | message: 'Expected function name to be kebab-case', 31 | }, 32 | ], 33 | 'scss/at-if-closing-brace-newline-after': 'always-last-in-chain', 34 | 'scss/at-if-closing-brace-space-after': 'always-intermediate', 35 | 'scss/at-mixin-argumentless-call-parentheses': 'never', 36 | 'scss/at-mixin-parentheses-space-before': 'never', 37 | 'scss/at-mixin-pattern': [ 38 | '^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$', 39 | { 40 | message: 'Expected mixin name to be kebab-case', 41 | }, 42 | ], 43 | 'scss/at-rule-conditional-no-parentheses': true, 44 | 'scss/dollar-variable-colon-space-after': 'always-single-line', 45 | 'scss/dollar-variable-colon-space-before': 'never', 46 | 'scss/dollar-variable-empty-line-before': [ 47 | 'always', 48 | { 49 | except: ['after-dollar-variable', 'first-nested'], 50 | ignore: ['after-comment', 'inside-single-line-block'], 51 | }, 52 | ], 53 | 'scss/dollar-variable-pattern': [ 54 | '^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$', 55 | { 56 | message: 'Expected variable to be kebab-case', 57 | }, 58 | ], 59 | 'scss/double-slash-comment-empty-line-before': [ 60 | 'always', 61 | { 62 | except: ['first-nested'], 63 | ignore: ['between-comments', 'stylelint-commands'], 64 | }, 65 | ], 66 | 'scss/double-slash-comment-whitespace-inside': 'always', 67 | 'scss/percent-placeholder-pattern': [ 68 | '^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$', 69 | { 70 | message: 'Expected placeholder to be kebab-case', 71 | }, 72 | ], 73 | }, 74 | }; 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-config-standard-scss", 3 | "version": "15.0.1", 4 | "description": "The standard shareable SCSS config for Stylelint", 5 | "keywords": [ 6 | "stylelint", 7 | "stylelint-config", 8 | "standard", 9 | "scss" 10 | ], 11 | "repository": "stylelint-scss/stylelint-config-standard-scss", 12 | "license": "MIT", 13 | "author": "Stylelint SCSS", 14 | "main": "index.js", 15 | "files": [ 16 | "index.js" 17 | ], 18 | "scripts": { 19 | "format": "prettier . --write --ignore-path=.prettierignore", 20 | "lint": "npm-run-all --parallel lint:*", 21 | "lint:formatting": "prettier . --check", 22 | "lint:js": "eslint .", 23 | "lint:md": "remark . --quiet --frail --ignore-path .gitignore", 24 | "release": "np", 25 | "test": "node --test", 26 | "watch": "node --test --watch" 27 | }, 28 | "dependencies": { 29 | "stylelint-config-recommended-scss": "^15.0.1", 30 | "stylelint-config-standard": "^38.0.0" 31 | }, 32 | "devDependencies": { 33 | "@stylelint/prettier-config": "^3.0.0", 34 | "@stylelint/remark-preset": "^5.1.1", 35 | "eslint": "^9.25.1", 36 | "eslint-config-stylelint": "^24.0.0", 37 | "np": "^10.2.0", 38 | "npm-run-all2": "^8.0.1", 39 | "prettier": "^3.5.3", 40 | "remark-cli": "^12.0.1", 41 | "stylelint": "^16.18.0" 42 | }, 43 | "peerDependencies": { 44 | "postcss": "^8.3.3", 45 | "stylelint": "^16.18.0" 46 | }, 47 | "peerDependenciesMeta": { 48 | "postcss": { 49 | "optional": true 50 | } 51 | }, 52 | "engines": { 53 | "node": ">=20" 54 | } 55 | } 56 | --------------------------------------------------------------------------------