From b014faac891f0c02d48378a882c1df6016c2a135 Mon Sep 17 00:00:00 2001 From: Brett Date: Sat, 16 Mar 2024 06:44:03 -0500 Subject: [PATCH] Add back stylistic rules removed in v10 --- README.md | 11 +-- __tests__/README.md | 4 +- ...t.mjs => at-rule-disallowed-list.test.mjs} | 4 +- __tests__/at-rule-no-unknown.test.mjs | 48 +++++++++++++ __tests__/at-rule-no-vendor-prefix.test.mjs | 51 ++++++++++++++ ...-rule.test.mjs => block-no-empty.test.mjs} | 4 +- .../block-opening-brace-space-before.test.mjs | 52 ++++++++++++++ __tests__/color-hex-case.test.mjs | 49 +++++++++++++ ...gth.test.mjs => color-hex-length.test.mjs} | 2 +- ...-keyword.test.mjs => color-named.test.mjs} | 6 +- ...test.mjs => color-no-invalid-hex.test.mjs} | 2 +- .../declaration-bang-space-after.test.mjs | 52 ++++++++++++++ .../declaration-bang-space-before.test.mjs | 50 ++++++++++++++ ...ion-block-semicolon-newline-after.test.mjs | 49 +++++++++++++ ...tion-block-semicolon-space-before.test.mjs | 47 +++++++++++++ ...lock-single-line-max-declarations.test.mjs | 50 ++++++++++++++ ...laration-block-trailing-semicolon.test.mjs | 57 +++++++++++++++ .../declaration-colon-space-after.test.mjs | 49 +++++++++++++ ...> declaration-colon-space-before.test.mjs} | 28 +++----- ...n-property-value-disallowed-list.test.mjs} | 6 +- __tests__/function-comma-space-after.test.mjs | 50 ++++++++++++++ ...function-parentheses-space-inside.test.mjs | 52 ++++++++++++++ ....test.mjs => function-url-quotes.test.mjs} | 2 +- __tests__/indentation.test.mjs | 49 +++++++++++++ ....test.mjs => length-zero-no-unit.test.mjs} | 2 +- ...th.test.mjs => max-nesting-depth.test.mjs} | 16 ++--- ...dia-feature-name-no-vendor-prefix.test.mjs | 51 ++++++++++++++ ...-feature-parentheses-space-inside.test.mjs | 53 ++++++++++++++ .../no-missing-end-of-source-newline.test.mjs | 45 ++++++++++++ __tests__/number-leading-zero.test.mjs | 49 +++++++++++++ __tests__/number-no-trailing-zeros.test.mjs | 49 +++++++++++++ ....test.mjs => property-no-unknown.test.mjs} | 2 +- __tests__/property-no-vendor-prefix.test.mjs | 50 ++++++++++++++ ...st.mjs => rule-empty-line-before.test.mjs} | 2 +- ...at-extend-no-missing-placeholder.test.mjs} | 2 +- __tests__/scss-at-function-pattern.test.mjs | 49 +++++++++++++ ...partial-extension-disallowed-list.test.mjs | 60 ++++++++++++++++ __tests__/scss-at-rule-no-unknown.test.mjs | 48 +++++++++++++ ...dollar-variable-colon-space-after.test.mjs | 48 +++++++++++++ ...ollar-variable-colon-space-before.test.mjs | 48 +++++++++++++ .../scss-dollar-variable-pattern.test.mjs | 47 +++++++++++++ ...ad-no-partial-leading-underscore.test.mjs} | 2 +- .../scss-no-global-function-names.test.mjs | 49 +++++++++++++ .../scss-percent-placeholder-pattern.mjs | 49 +++++++++++++ ...or-no-redundant-nesting-selector.test.mjs} | 2 +- ...st.mjs => selector-class-pattern.test.mjs} | 2 +- ...selector-list-comma-newline-after.test.mjs | 56 +++++++++++++++ ... selector-max-compound-selectors.test.mjs} | 2 +- ...ctor.test.mjs => selector-max-id.test.mjs} | 2 +- ...s => selector-no-qualifying-type.test.mjs} | 2 +- __tests__/selector-no-vendor-prefix.test.mjs | 50 ++++++++++++++ ...or-pseudo-element-colon-notation.test.mjs} | 2 +- ...elector-pseudo-element-no-unknown.test.mjs | 49 +++++++++++++ ...and-property-no-redundant-values.test.mjs} | 2 +- __tests__/string-quotes.test.mjs | 51 ++++++++++++++ __tests__/value-no-vendor-prefix.test.mjs | 49 +++++++++++++ __tests__/vendor-prefixes.test.mjs | 69 ------------------- index.js | 47 +++++++++---- package.json | 1 + 59 files changed, 1740 insertions(+), 141 deletions(-) rename __tests__/{debug-statement.test.mjs => at-rule-disallowed-list.test.mjs} (91%) create mode 100644 __tests__/at-rule-no-unknown.test.mjs create mode 100644 __tests__/at-rule-no-vendor-prefix.test.mjs rename __tests__/{empty-rule.test.mjs => block-no-empty.test.mjs} (91%) create mode 100644 __tests__/block-opening-brace-space-before.test.mjs create mode 100644 __tests__/color-hex-case.test.mjs rename __tests__/{hex-length.test.mjs => color-hex-length.test.mjs} (93%) rename __tests__/{color-keyword.test.mjs => color-named.test.mjs} (89%) rename __tests__/{hex-validation.test.mjs => color-no-invalid-hex.test.mjs} (93%) create mode 100644 __tests__/declaration-bang-space-after.test.mjs create mode 100644 __tests__/declaration-bang-space-before.test.mjs create mode 100644 __tests__/declaration-block-semicolon-newline-after.test.mjs create mode 100644 __tests__/declaration-block-semicolon-space-before.test.mjs create mode 100644 __tests__/declaration-block-single-line-max-declarations.test.mjs create mode 100644 __tests__/declaration-block-trailing-semicolon.test.mjs create mode 100644 __tests__/declaration-colon-space-after.test.mjs rename __tests__/{name-format.test.mjs => declaration-colon-space-before.test.mjs} (52%) rename __tests__/{border-none.test.mjs => declaration-property-value-disallowed-list.test.mjs} (86%) create mode 100644 __tests__/function-comma-space-after.test.mjs create mode 100644 __tests__/function-parentheses-space-inside.test.mjs rename __tests__/{url-quotes.test.mjs => function-url-quotes.test.mjs} (93%) create mode 100644 __tests__/indentation.test.mjs rename __tests__/{zero-unit.test.mjs => length-zero-no-unit.test.mjs} (92%) rename __tests__/{nesting-depth.test.mjs => max-nesting-depth.test.mjs} (67%) create mode 100644 __tests__/media-feature-name-no-vendor-prefix.test.mjs create mode 100644 __tests__/media-feature-parentheses-space-inside.test.mjs create mode 100644 __tests__/no-missing-end-of-source-newline.test.mjs create mode 100644 __tests__/number-leading-zero.test.mjs create mode 100644 __tests__/number-no-trailing-zeros.test.mjs rename __tests__/{property-spelling.test.mjs => property-no-unknown.test.mjs} (94%) create mode 100644 __tests__/property-no-vendor-prefix.test.mjs rename __tests__/{empty-line-between-blocks.test.mjs => rule-empty-line-before.test.mjs} (93%) rename __tests__/{placeholder-in-extend.test.mjs => scss-at-extend-no-missing-placeholder.test.mjs} (91%) create mode 100644 __tests__/scss-at-function-pattern.test.mjs create mode 100644 __tests__/scss-at-import-partial-extension-disallowed-list.test.mjs create mode 100644 __tests__/scss-at-rule-no-unknown.test.mjs create mode 100644 __tests__/scss-dollar-variable-colon-space-after.test.mjs create mode 100644 __tests__/scss-dollar-variable-colon-space-before.test.mjs create mode 100644 __tests__/scss-dollar-variable-pattern.test.mjs rename __tests__/{import-path.test.mjs => scss-load-no-partial-leading-underscore.test.mjs} (95%) create mode 100644 __tests__/scss-no-global-function-names.test.mjs create mode 100644 __tests__/scss-percent-placeholder-pattern.mjs rename __tests__/{unnecessary-parent-reference.test.mjs => scss-selector-no-redundant-nesting-selector.test.mjs} (91%) rename __tests__/{selector-format.test.mjs => selector-class-pattern.test.mjs} (95%) create mode 100644 __tests__/selector-list-comma-newline-after.test.mjs rename __tests__/{selector-depth.test.mjs => selector-max-compound-selectors.test.mjs} (93%) rename __tests__/{id-selector.test.mjs => selector-max-id.test.mjs} (93%) rename __tests__/{qualifying-element.test.mjs => selector-no-qualifying-type.test.mjs} (95%) create mode 100644 __tests__/selector-no-vendor-prefix.test.mjs rename __tests__/{pseudo-element.test.mjs => selector-pseudo-element-colon-notation.test.mjs} (92%) create mode 100644 __tests__/selector-pseudo-element-no-unknown.test.mjs rename __tests__/{shorthand.test.mjs => shorthand-property-no-redundant-values.test.mjs} (91%) create mode 100644 __tests__/string-quotes.test.mjs create mode 100644 __tests__/value-no-vendor-prefix.test.mjs delete mode 100644 __tests__/vendor-prefixes.test.mjs diff --git a/README.md b/README.md index f92f673..b533e78 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,13 @@ 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. This config: -- bundles the [`stylelint-scss` plugin pack](https://github.com/stylelint-scss/stylelint-scss) and turns on its rules that check for possible errors -- bundles the [`postcss-scss` custom syntax](https://github.com/postcss/postcss-scss) and configures it -- has a peer dependency on [`stylelint ^16.1.0`](https://github.com/stylelint/stylelint) You'll need to install this package in your project -- has a peer dependency on [`postcss ^8.4.21`](https://github.com/postcss/postcss) You'll need to install this package in your project +- includes the [`stylelint-scss` plugin module](https://github.com/stylelint-scss/stylelint-scss) and turns on rules for SCSS specific code +- includes the [`@stylistic/stylelint-plugin` plugin module](https://github.com/stylelint-stylistic/stylelint-stylistic) and turns on rules for stylistic settings +- includes the [`postcss-scss` custom syntax module](https://github.com/postcss/postcss-scss) and configures it +- has a peer dependency on [`stylelint`](https://github.com/stylelint/stylelint) + - You'll need to install this package in your project +- has a peer dependency on [`postcss`](https://github.com/postcss/postcss) + - You'll need to install this package in your project # Translations diff --git a/__tests__/README.md b/__tests__/README.md index 61cd463..58a47b6 100644 --- a/__tests__/README.md +++ b/__tests__/README.md @@ -1,8 +1,8 @@ # How to add tests -* Create your test file named after the scss lint your you are adding a stylelint rule for. For example, `__tests___/unit/bang-format.test.mjs` +* Create your test file named after the scss lint your you are adding a stylelint rule for. For example, `__tests___/color-hex-case.test.mjs` * Copy the code from one of the other tests into your test new file -* Update the test so you have .scss code that will produce lint you want to test for +* Update the test so you have SCSS code that will produce lint you want to test for * Look for warnings it generates * Copy expected text to test file * Run tests again and refine until they pass diff --git a/__tests__/debug-statement.test.mjs b/__tests__/at-rule-disallowed-list.test.mjs similarity index 91% rename from __tests__/debug-statement.test.mjs rename to __tests__/at-rule-disallowed-list.test.mjs index 378a42d..88014d4 100644 --- a/__tests__/debug-statement.test.mjs +++ b/__tests__/at-rule-disallowed-list.test.mjs @@ -5,11 +5,11 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with debug statement scss', () => { +describe('flags warnings with at-rule-disallowed lint', () => { const invalidScss = ( `$color-blue: #1c94c6; -.debug { +.test-selector { @debug $color-blue; } `); diff --git a/__tests__/at-rule-no-unknown.test.mjs b/__tests__/at-rule-no-unknown.test.mjs new file mode 100644 index 0000000..d9276d4 --- /dev/null +++ b/__tests__/at-rule-no-unknown.test.mjs @@ -0,0 +1,48 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with at-rule-no-unknown lint', () => { + const invalidScss = ( +`@unknown { color: #fff; } + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected unknown at-rule "@unknown" (scss/at-rule-no-unknown)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/at-rule-no-unknown', + ], + ); + }); +}); diff --git a/__tests__/at-rule-no-vendor-prefix.test.mjs b/__tests__/at-rule-no-vendor-prefix.test.mjs new file mode 100644 index 0000000..74f1c8e --- /dev/null +++ b/__tests__/at-rule-no-vendor-prefix.test.mjs @@ -0,0 +1,51 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with at-rule-no-vendor-prefix lint', () => { + const invalidScss = ( +`@-webkit-keyframes anim { + 0% { + opacity: 0; + } +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected vendor-prefixed at-rule "@-webkit-keyframes" (at-rule-no-vendor-prefix)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'at-rule-no-vendor-prefix', + ], + ); + }); +}); diff --git a/__tests__/empty-rule.test.mjs b/__tests__/block-no-empty.test.mjs similarity index 91% rename from __tests__/empty-rule.test.mjs rename to __tests__/block-no-empty.test.mjs index 914b0f2..6b5caca 100644 --- a/__tests__/empty-rule.test.mjs +++ b/__tests__/block-no-empty.test.mjs @@ -5,9 +5,9 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with empty rule', () => { +describe('flags warnings with block-no-empty lint', () => { const invalidScss = ( -`.cat { +`.test-selector { } `); diff --git a/__tests__/block-opening-brace-space-before.test.mjs b/__tests__/block-opening-brace-space-before.test.mjs new file mode 100644 index 0000000..7197736 --- /dev/null +++ b/__tests__/block-opening-brace-space-before.test.mjs @@ -0,0 +1,52 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with block-opening-brace-space-before lint', () => { + const invalidScss = ( +`.test-selector{ color: #fff; } + +.test-selector +{ color: #fff; } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single space before "{" (@stylistic/block-opening-brace-space-before)', + 'Expected single space before "{" (@stylistic/block-opening-brace-space-before)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/block-opening-brace-space-before', + '@stylistic/block-opening-brace-space-before', + ], + ); + }); +}); diff --git a/__tests__/color-hex-case.test.mjs b/__tests__/color-hex-case.test.mjs new file mode 100644 index 0000000..97fd572 --- /dev/null +++ b/__tests__/color-hex-case.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with color-hex-case lint', () => { + const invalidScss = ( +`.test-selector { + color: #FFF; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected "#FFF" to be "#fff" (@stylistic/color-hex-case)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/color-hex-case', + ], + ); + }); +}); diff --git a/__tests__/hex-length.test.mjs b/__tests__/color-hex-length.test.mjs similarity index 93% rename from __tests__/hex-length.test.mjs rename to __tests__/color-hex-length.test.mjs index 1d16762..0720d71 100644 --- a/__tests__/hex-length.test.mjs +++ b/__tests__/color-hex-length.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with hex color length', () => { +describe('flags warnings with color-hex-length lint', () => { const invalidScss = ( `.hexlength { color: #ff22ee; diff --git a/__tests__/color-keyword.test.mjs b/__tests__/color-named.test.mjs similarity index 89% rename from __tests__/color-keyword.test.mjs rename to __tests__/color-named.test.mjs index c0cbb95..3deac4c 100644 --- a/__tests__/color-keyword.test.mjs +++ b/__tests__/color-named.test.mjs @@ -5,10 +5,10 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with named color keyword', () => { +describe('flags warnings with color-named lint', () => { const invalidScss = ( -`.colorkeyword { - color: green; +`.test-selector { + color: green; } `); diff --git a/__tests__/hex-validation.test.mjs b/__tests__/color-no-invalid-hex.test.mjs similarity index 93% rename from __tests__/hex-validation.test.mjs rename to __tests__/color-no-invalid-hex.test.mjs index d61c9e5..32e8a0b 100644 --- a/__tests__/hex-validation.test.mjs +++ b/__tests__/color-no-invalid-hex.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with hex validation', () => { +describe('flags warnings with color-no-invalid-hex lint', () => { const invalidScss = ( `.hex-validation { background: #ab; // Clearly a typo diff --git a/__tests__/declaration-bang-space-after.test.mjs b/__tests__/declaration-bang-space-after.test.mjs new file mode 100644 index 0000000..8dd5a1c --- /dev/null +++ b/__tests__/declaration-bang-space-after.test.mjs @@ -0,0 +1,52 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-bang-space-after lint', () => { + const invalidScss = ( +`.test-selector { color: #fff ! important; } +.test-selector { color: #fff! important; } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 3); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected whitespace after "!" (@stylistic/declaration-bang-space-after)', + 'Unexpected whitespace after "!" (@stylistic/declaration-bang-space-after)', + 'Expected single space before "!" (@stylistic/declaration-bang-space-before)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-bang-space-after', + '@stylistic/declaration-bang-space-after', + '@stylistic/declaration-bang-space-before', + ], + ); + }); +}); diff --git a/__tests__/declaration-bang-space-before.test.mjs b/__tests__/declaration-bang-space-before.test.mjs new file mode 100644 index 0000000..96b5e30 --- /dev/null +++ b/__tests__/declaration-bang-space-before.test.mjs @@ -0,0 +1,50 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-bang-space-before lint', () => { + const invalidScss = ( +`.test-selector { color: #fff!important; } +.test-selector { color: #fff !important; } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single space before "!" (@stylistic/declaration-bang-space-before)', + 'Expected single space before "!" (@stylistic/declaration-bang-space-before)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-bang-space-before', + '@stylistic/declaration-bang-space-before', + ], + ); + }); +}); diff --git a/__tests__/declaration-block-semicolon-newline-after.test.mjs b/__tests__/declaration-block-semicolon-newline-after.test.mjs new file mode 100644 index 0000000..13acbe8 --- /dev/null +++ b/__tests__/declaration-block-semicolon-newline-after.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-block-semicolon-newline-after lint', () => { + const invalidScss = (`.test-selector { color: #fff; top: 0; }`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 3); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', + 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)', + 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-block-semicolon-newline-after', + '@stylistic/no-missing-end-of-source-newline', + 'declaration-block-single-line-max-declarations' + ], + ); + }); +}); diff --git a/__tests__/declaration-block-semicolon-space-before.test.mjs b/__tests__/declaration-block-semicolon-space-before.test.mjs new file mode 100644 index 0000000..2f1ff09 --- /dev/null +++ b/__tests__/declaration-block-semicolon-space-before.test.mjs @@ -0,0 +1,47 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-block-semicolon-space-before lint', () => { + const invalidScss = (`.test-selector { color: #fff ; }`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected whitespace before ";" (@stylistic/declaration-block-semicolon-space-before)', + 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-block-semicolon-space-before', + '@stylistic/no-missing-end-of-source-newline' + ], + ); + }); +}); diff --git a/__tests__/declaration-block-single-line-max-declarations.test.mjs b/__tests__/declaration-block-single-line-max-declarations.test.mjs new file mode 100644 index 0000000..18da2ba --- /dev/null +++ b/__tests__/declaration-block-single-line-max-declarations.test.mjs @@ -0,0 +1,50 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-block-single-line-max-declarations lint', () => { + const invalidScss = (` +.test-selector { color: #fff; top: 0; } + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', + 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-block-semicolon-newline-after', + 'declaration-block-single-line-max-declarations' + ], + ); + }); +}); diff --git a/__tests__/declaration-block-trailing-semicolon.test.mjs b/__tests__/declaration-block-trailing-semicolon.test.mjs new file mode 100644 index 0000000..f174897 --- /dev/null +++ b/__tests__/declaration-block-trailing-semicolon.test.mjs @@ -0,0 +1,57 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-block-trailing-semicolon lint', () => { + const invalidScss = ( +`.test-selector { color: #fff } +.test-selector { background: #000; color: #fff } +.test-selector { @include foo } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 5); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected newline after ";" (@stylistic/declaration-block-semicolon-newline-after)', + 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', + 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', + 'Expected a trailing semicolon (@stylistic/declaration-block-trailing-semicolon)', + 'Expected no more than 1 declaration (declaration-block-single-line-max-declarations)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-block-semicolon-newline-after', + '@stylistic/declaration-block-trailing-semicolon', + '@stylistic/declaration-block-trailing-semicolon', + '@stylistic/declaration-block-trailing-semicolon', + 'declaration-block-single-line-max-declarations' + ], + ); + }); +}); diff --git a/__tests__/declaration-colon-space-after.test.mjs b/__tests__/declaration-colon-space-after.test.mjs new file mode 100644 index 0000000..9037b0f --- /dev/null +++ b/__tests__/declaration-colon-space-after.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with declaration-colon-space-after lint', () => { + const invalidScss = ( +`.test-selector { + box-shadow:0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, 0.8); +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single space after ":" with a single-line declaration (@stylistic/declaration-colon-space-after)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/declaration-colon-space-after', + ], + ); + }); +}); diff --git a/__tests__/name-format.test.mjs b/__tests__/declaration-colon-space-before.test.mjs similarity index 52% rename from __tests__/name-format.test.mjs rename to __tests__/declaration-colon-space-before.test.mjs index c4b4d30..4c91099 100644 --- a/__tests__/name-format.test.mjs +++ b/__tests__/declaration-colon-space-before.test.mjs @@ -5,20 +5,14 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with invalid name format', () => { +describe('flags warnings with declaration-colon-space-before lint', () => { const invalidScss = ( -`@function calculationFunction($some-number, $another-number) { - @return $some-number + $another-number; +`.test-selector { + color : #fff; } -@mixin myMixin() { - color: #fff; -} - -$myVar: 10px; - -%placeHolder { - color: #f00; +.test-selector { + color :#fff; } `); @@ -43,9 +37,9 @@ $myVar: 10px; assert.deepEqual( result.results[0].warnings.map((w) => w.text), [ - 'Expected @function name to match specified pattern (scss/at-function-pattern)', - 'Expected $ variable name to match specified pattern (scss/dollar-variable-pattern)', - 'Expected %-placeholder "%placeHolder" to match specified pattern (scss/percent-placeholder-pattern)', + 'Expected single space after ":" with a single-line declaration (@stylistic/declaration-colon-space-after)', + 'Unexpected whitespace before ":" (@stylistic/declaration-colon-space-before)', + 'Unexpected whitespace before ":" (@stylistic/declaration-colon-space-before)' ], ); }); @@ -54,9 +48,9 @@ $myVar: 10px; assert.deepEqual( result.results[0].warnings.map((w) => w.rule), [ - 'scss/at-function-pattern', - 'scss/dollar-variable-pattern', - 'scss/percent-placeholder-pattern', + '@stylistic/declaration-colon-space-after', + '@stylistic/declaration-colon-space-before', + '@stylistic/declaration-colon-space-before' ], ); }); diff --git a/__tests__/border-none.test.mjs b/__tests__/declaration-property-value-disallowed-list.test.mjs similarity index 86% rename from __tests__/border-none.test.mjs rename to __tests__/declaration-property-value-disallowed-list.test.mjs index f809cb5..95ce7cb 100644 --- a/__tests__/border-none.test.mjs +++ b/__tests__/declaration-property-value-disallowed-list.test.mjs @@ -5,10 +5,10 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with border none', () => { +describe('flags warnings with declaration-property-value-disallowed-list border none lint', () => { const invalidScss = ( -`.borderzero { - border: none; +`.test-selector { + border: none; } `); diff --git a/__tests__/function-comma-space-after.test.mjs b/__tests__/function-comma-space-after.test.mjs new file mode 100644 index 0000000..d7f9cdb --- /dev/null +++ b/__tests__/function-comma-space-after.test.mjs @@ -0,0 +1,50 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with function-comma-space-after lint', () => { + const invalidScss = ( +`.test-selector { transform: translate(1,1); } +.test-selector { transform: translate(1 ,1); } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single space after "," in a single-line function (@stylistic/function-comma-space-after)', + 'Expected single space after "," in a single-line function (@stylistic/function-comma-space-after)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/function-comma-space-after', + '@stylistic/function-comma-space-after' + ], + ); + }); +}); diff --git a/__tests__/function-parentheses-space-inside.test.mjs b/__tests__/function-parentheses-space-inside.test.mjs new file mode 100644 index 0000000..6b79ef3 --- /dev/null +++ b/__tests__/function-parentheses-space-inside.test.mjs @@ -0,0 +1,52 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with function-parentheses-space-inside lint', () => { + const invalidScss = ( +`.test-selector { transform: translate( 1, 1 ); } +.test-selector { transform: translate(1, 1 ); } +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 3); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected whitespace after "(" (@stylistic/function-parentheses-space-inside)', + 'Unexpected whitespace before ")" (@stylistic/function-parentheses-space-inside)', + 'Unexpected whitespace before ")" (@stylistic/function-parentheses-space-inside)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/function-parentheses-space-inside', + '@stylistic/function-parentheses-space-inside', + '@stylistic/function-parentheses-space-inside' + ], + ); + }); +}); diff --git a/__tests__/url-quotes.test.mjs b/__tests__/function-url-quotes.test.mjs similarity index 93% rename from __tests__/url-quotes.test.mjs rename to __tests__/function-url-quotes.test.mjs index 6196c0d..e4a90d1 100644 --- a/__tests__/url-quotes.test.mjs +++ b/__tests__/function-url-quotes.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with missing url quotes', () => { +describe('flags warnings with function-url-quotes lint', () => { const invalidScss = ( `.quotes-url { background: url(example.png); diff --git a/__tests__/indentation.test.mjs b/__tests__/indentation.test.mjs new file mode 100644 index 0000000..ac74957 --- /dev/null +++ b/__tests__/indentation.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with indentation lint', () => { + const invalidScss = ( +`.test-selector { +color: #fff; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected indentation of 2 spaces (@stylistic/indentation)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/indentation', + ], + ); + }); +}); diff --git a/__tests__/zero-unit.test.mjs b/__tests__/length-zero-no-unit.test.mjs similarity index 92% rename from __tests__/zero-unit.test.mjs rename to __tests__/length-zero-no-unit.test.mjs index 4abc359..a2f1eac 100644 --- a/__tests__/zero-unit.test.mjs +++ b/__tests__/length-zero-no-unit.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with zero unit', () => { +describe('flags warnings with length-zero-no-unit lint', () => { const invalidScss = ( `.zerounit { margin: 0px; diff --git a/__tests__/nesting-depth.test.mjs b/__tests__/max-nesting-depth.test.mjs similarity index 67% rename from __tests__/nesting-depth.test.mjs rename to __tests__/max-nesting-depth.test.mjs index 12592ef..b19ce1d 100644 --- a/__tests__/nesting-depth.test.mjs +++ b/__tests__/max-nesting-depth.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with nesting depth', () => { +describe('flags warnings with max-nesting-depth lint', () => { const invalidScss = ( `.one { .two { @@ -20,9 +20,7 @@ describe('flags warnings with nesting depth', () => { } .three { - .four { - color: #f00; - } + color: #f00; } } } @@ -42,16 +40,14 @@ describe('flags warnings with nesting depth', () => { }); it('flags warnings', () => { - assert.equal(result.results[0].warnings.length, 3); + assert.equal(result.results[0].warnings.length, 1); }); it('correct warning text', () => { assert.deepEqual( result.results[0].warnings.map((w) => w.text), [ - 'Expected nesting depth to be no more than 1 (max-nesting-depth)', - 'Expected nesting depth to be no more than 1 (max-nesting-depth)', - 'Expected ".one .two .three .four" to have no more than 3 compound selectors (selector-max-compound-selectors)', + 'Expected nesting depth to be no more than 1 (max-nesting-depth)' ], ); }); @@ -60,9 +56,7 @@ describe('flags warnings with nesting depth', () => { assert.deepEqual( result.results[0].warnings.map((w) => w.rule), [ - 'max-nesting-depth', - 'max-nesting-depth', - 'selector-max-compound-selectors', + 'max-nesting-depth' ], ); }); diff --git a/__tests__/media-feature-name-no-vendor-prefix.test.mjs b/__tests__/media-feature-name-no-vendor-prefix.test.mjs new file mode 100644 index 0000000..d50f827 --- /dev/null +++ b/__tests__/media-feature-name-no-vendor-prefix.test.mjs @@ -0,0 +1,51 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with media-feature-name-no-vendor-prefix lint', () => { + const invalidScss = (`@media (-webkit-min-device-pixel-ratio: 1) { + .test-selector { + color: #fff; + } +} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected vendor-prefix (media-feature-name-no-vendor-prefix)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'media-feature-name-no-vendor-prefix' + ], + ); + }); +}); diff --git a/__tests__/media-feature-parentheses-space-inside.test.mjs b/__tests__/media-feature-parentheses-space-inside.test.mjs new file mode 100644 index 0000000..6e2073d --- /dev/null +++ b/__tests__/media-feature-parentheses-space-inside.test.mjs @@ -0,0 +1,53 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with media-feature-parentheses-space-inside lint', () => { + const invalidScss = (`@media ( max-width: 300px ) { + .test-selector { + color: #fff; + } +} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected whitespace after "(" (@stylistic/media-feature-parentheses-space-inside)', + 'Unexpected whitespace before ")" (@stylistic/media-feature-parentheses-space-inside)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/media-feature-parentheses-space-inside', + '@stylistic/media-feature-parentheses-space-inside' + ], + ); + }); +}); diff --git a/__tests__/no-missing-end-of-source-newline.test.mjs b/__tests__/no-missing-end-of-source-newline.test.mjs new file mode 100644 index 0000000..7aa7df4 --- /dev/null +++ b/__tests__/no-missing-end-of-source-newline.test.mjs @@ -0,0 +1,45 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with no-missing-end-of-source-newline lint', () => { + const invalidScss = (`.test-selector { color: #fff; }`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected missing end-of-source newline (@stylistic/no-missing-end-of-source-newline)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/no-missing-end-of-source-newline', + ], + ); + }); +}); diff --git a/__tests__/number-leading-zero.test.mjs b/__tests__/number-leading-zero.test.mjs new file mode 100644 index 0000000..cd2802a --- /dev/null +++ b/__tests__/number-leading-zero.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with number-leading-zero lint', () => { + const invalidScss = ( +`.test-selector { + line-height: .5em; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected a leading zero (@stylistic/number-leading-zero)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/number-leading-zero', + ], + ); + }); +}); diff --git a/__tests__/number-no-trailing-zeros.test.mjs b/__tests__/number-no-trailing-zeros.test.mjs new file mode 100644 index 0000000..392eef0 --- /dev/null +++ b/__tests__/number-no-trailing-zeros.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with number-no-trailing-zeros lint', () => { + const invalidScss = ( +`.test-selector { + top: 1.0px; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected trailing zero(s) (@stylistic/number-no-trailing-zeros)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/number-no-trailing-zeros', + ], + ); + }); +}); diff --git a/__tests__/property-spelling.test.mjs b/__tests__/property-no-unknown.test.mjs similarity index 94% rename from __tests__/property-spelling.test.mjs rename to __tests__/property-no-unknown.test.mjs index 9c9daab..ec9b599 100644 --- a/__tests__/property-spelling.test.mjs +++ b/__tests__/property-no-unknown.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with property spelling', () => { +describe('flags warnings with property-no-unknown lint', () => { const invalidScss = ( `.property-spelling { diplay: none; // "display" is spelled incorrectly diff --git a/__tests__/property-no-vendor-prefix.test.mjs b/__tests__/property-no-vendor-prefix.test.mjs new file mode 100644 index 0000000..17994d3 --- /dev/null +++ b/__tests__/property-no-vendor-prefix.test.mjs @@ -0,0 +1,50 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with property-no-vendor-prefix lint', () => { + const invalidScss = ( +`.test-selector { + -webkit-transform: scale(1); +} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected vendor-prefix "-webkit-transform" (property-no-vendor-prefix)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'property-no-vendor-prefix', + ], + ); + }); +}); diff --git a/__tests__/empty-line-between-blocks.test.mjs b/__tests__/rule-empty-line-before.test.mjs similarity index 93% rename from __tests__/empty-line-between-blocks.test.mjs rename to __tests__/rule-empty-line-before.test.mjs index a6440f4..82d9cf9 100644 --- a/__tests__/empty-line-between-blocks.test.mjs +++ b/__tests__/rule-empty-line-before.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with missing empty line between blocks', () => { +describe('flags warnings with rule-empty-line-before lint', () => { const invalidScss = ( `p { margin: 0; diff --git a/__tests__/placeholder-in-extend.test.mjs b/__tests__/scss-at-extend-no-missing-placeholder.test.mjs similarity index 91% rename from __tests__/placeholder-in-extend.test.mjs rename to __tests__/scss-at-extend-no-missing-placeholder.test.mjs index d5f2a45..b065cf3 100644 --- a/__tests__/placeholder-in-extend.test.mjs +++ b/__tests__/scss-at-extend-no-missing-placeholder.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with missing placeholder with @extend scss', () => { +describe('flags warnings with scss/at-extend-no-missing-placeholder lint', () => { const invalidScss = ( `.fatal { @extend .error; diff --git a/__tests__/scss-at-function-pattern.test.mjs b/__tests__/scss-at-function-pattern.test.mjs new file mode 100644 index 0000000..c7a1a3d --- /dev/null +++ b/__tests__/scss-at-function-pattern.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/at-function-pattern lint', () => { + const invalidScss = ( +`@function calculationFunction($some-number, $another-number) { + @return $some-number + $another-number; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected @function name to match specified pattern (scss/at-function-pattern)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/at-function-pattern', + ], + ); + }); +}); diff --git a/__tests__/scss-at-import-partial-extension-disallowed-list.test.mjs b/__tests__/scss-at-import-partial-extension-disallowed-list.test.mjs new file mode 100644 index 0000000..3df8c29 --- /dev/null +++ b/__tests__/scss-at-import-partial-extension-disallowed-list.test.mjs @@ -0,0 +1,60 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/at-import-partial-extension-disallowed-list lint', () => { + const invalidScss = ( + `@import 'foo/_bar.scss'; +@import '_bar.scss'; +@import '_bar'; +@import 'bar.scss'; +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 6); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', + 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', + 'Unexpected extension ".scss" in imported partial name (scss/at-import-partial-extension-disallowed-list)', + 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', + 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', + 'Unexpected leading underscore in imported partial name (scss/load-no-partial-leading-underscore)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/at-import-partial-extension-disallowed-list', + 'scss/at-import-partial-extension-disallowed-list', + 'scss/at-import-partial-extension-disallowed-list', + 'scss/load-no-partial-leading-underscore', + 'scss/load-no-partial-leading-underscore', + 'scss/load-no-partial-leading-underscore', + ], + ); + }); +}); diff --git a/__tests__/scss-at-rule-no-unknown.test.mjs b/__tests__/scss-at-rule-no-unknown.test.mjs new file mode 100644 index 0000000..1370a97 --- /dev/null +++ b/__tests__/scss-at-rule-no-unknown.test.mjs @@ -0,0 +1,48 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/at-rule-no-unknown lint', () => { + const invalidScss = ( +`@unknown { color: #fff; } + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected unknown at-rule "@unknown" (scss/at-rule-no-unknown)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/at-rule-no-unknown', + ], + ); + }); +}); diff --git a/__tests__/scss-dollar-variable-colon-space-after.test.mjs b/__tests__/scss-dollar-variable-colon-space-after.test.mjs new file mode 100644 index 0000000..bc0d3b1 --- /dev/null +++ b/__tests__/scss-dollar-variable-colon-space-after.test.mjs @@ -0,0 +1,48 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/dollar-variable-colon-space-after lint', () => { + const invalidScss = ( +`a { $var:10px;} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single space after ":" (scss/dollar-variable-colon-space-after)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/dollar-variable-colon-space-after' + ], + ); + }); +}); diff --git a/__tests__/scss-dollar-variable-colon-space-before.test.mjs b/__tests__/scss-dollar-variable-colon-space-before.test.mjs new file mode 100644 index 0000000..d1ef046 --- /dev/null +++ b/__tests__/scss-dollar-variable-colon-space-before.test.mjs @@ -0,0 +1,48 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/dollar-variable-colon-space-before lint', () => { + const invalidScss = ( +`a { $var : 10px;} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected whitespace before ":" (scss/dollar-variable-colon-space-before)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/dollar-variable-colon-space-before' + ], + ); + }); +}); diff --git a/__tests__/scss-dollar-variable-pattern.test.mjs b/__tests__/scss-dollar-variable-pattern.test.mjs new file mode 100644 index 0000000..baba25d --- /dev/null +++ b/__tests__/scss-dollar-variable-pattern.test.mjs @@ -0,0 +1,47 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with invalid scss/dollar-variable-pattern lint', () => { + const invalidScss = ( +`$myVar: 10px; +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected $ variable name to match specified pattern (scss/dollar-variable-pattern)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/dollar-variable-pattern', + ], + ); + }); +}); diff --git a/__tests__/import-path.test.mjs b/__tests__/scss-load-no-partial-leading-underscore.test.mjs similarity index 95% rename from __tests__/import-path.test.mjs rename to __tests__/scss-load-no-partial-leading-underscore.test.mjs index e2b3f0b..70b4b71 100644 --- a/__tests__/import-path.test.mjs +++ b/__tests__/scss-load-no-partial-leading-underscore.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with incorrect scss import path', () => { +describe('flags warnings with scss/load-no-partial-leading-underscore lint', () => { const invalidScss = ( `@import 'foo/_bar.scss'; @import '_bar.scss'; diff --git a/__tests__/scss-no-global-function-names.test.mjs b/__tests__/scss-no-global-function-names.test.mjs new file mode 100644 index 0000000..517a2a9 --- /dev/null +++ b/__tests__/scss-no-global-function-names.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/no-global-function-names lint', () => { + const invalidScss = ( +`a { + background: adjust-color(#6b717f, $red: 15); +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected color.adjust instead of adjust-color (scss/no-global-function-names)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/no-global-function-names', + ], + ); + }); +}); diff --git a/__tests__/scss-percent-placeholder-pattern.mjs b/__tests__/scss-percent-placeholder-pattern.mjs new file mode 100644 index 0000000..3f40944 --- /dev/null +++ b/__tests__/scss-percent-placeholder-pattern.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with scss/percent-placeholder-pattern lint', () => { + const invalidScss = ( +`%placeHolder { + color: #f00; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected %-placeholder "%placeHolder" to match specified pattern (scss/percent-placeholder-pattern)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'scss/percent-placeholder-pattern', + ], + ); + }); +}); diff --git a/__tests__/unnecessary-parent-reference.test.mjs b/__tests__/scss-selector-no-redundant-nesting-selector.test.mjs similarity index 91% rename from __tests__/unnecessary-parent-reference.test.mjs rename to __tests__/scss-selector-no-redundant-nesting-selector.test.mjs index d664fb9..ff01f40 100644 --- a/__tests__/unnecessary-parent-reference.test.mjs +++ b/__tests__/scss-selector-no-redundant-nesting-selector.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with unnecessary parent reference', () => { +describe('flags warnings with scss/selector-no-redundant-nesting-selector lint', () => { const invalidScss = ( `.parentreference { & > .bar { diff --git a/__tests__/selector-format.test.mjs b/__tests__/selector-class-pattern.test.mjs similarity index 95% rename from __tests__/selector-format.test.mjs rename to __tests__/selector-class-pattern.test.mjs index 57fd126..abb05c3 100644 --- a/__tests__/selector-format.test.mjs +++ b/__tests__/selector-class-pattern.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with selector format', () => { +describe('flags warnings with selector-class-pattern lint', () => { const invalidScss = ( `.Foo { color: #f00; diff --git a/__tests__/selector-list-comma-newline-after.test.mjs b/__tests__/selector-list-comma-newline-after.test.mjs new file mode 100644 index 0000000..0d93c2e --- /dev/null +++ b/__tests__/selector-list-comma-newline-after.test.mjs @@ -0,0 +1,56 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with selector-list-comma-newline-after lint', () => { + const invalidScss = ( +`a, b { + color: #fff; +} + +a +, b { + color: #000; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected newline after "," (@stylistic/selector-list-comma-newline-after)', + 'Expected newline after "," (@stylistic/selector-list-comma-newline-after)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/selector-list-comma-newline-after', + '@stylistic/selector-list-comma-newline-after' + ], + ); + }); +}); diff --git a/__tests__/selector-depth.test.mjs b/__tests__/selector-max-compound-selectors.test.mjs similarity index 93% rename from __tests__/selector-depth.test.mjs rename to __tests__/selector-max-compound-selectors.test.mjs index bcc819c..8cef81f 100644 --- a/__tests__/selector-depth.test.mjs +++ b/__tests__/selector-max-compound-selectors.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with selector depth', () => { +describe('flags warnings with selector-max-compound-selectors lint', () => { const invalidScss = ( `.one .two .three > .four { color: #f00; diff --git a/__tests__/id-selector.test.mjs b/__tests__/selector-max-id.test.mjs similarity index 93% rename from __tests__/id-selector.test.mjs rename to __tests__/selector-max-id.test.mjs index e47d390..74af125 100644 --- a/__tests__/id-selector.test.mjs +++ b/__tests__/selector-max-id.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with ID selector', () => { +describe('flags warnings with selector-max-id lint', () => { const invalidScss = ( `#id-selector { color: #f00; diff --git a/__tests__/qualifying-element.test.mjs b/__tests__/selector-no-qualifying-type.test.mjs similarity index 95% rename from __tests__/qualifying-element.test.mjs rename to __tests__/selector-no-qualifying-type.test.mjs index 199d3a4..4c0e24c 100644 --- a/__tests__/qualifying-element.test.mjs +++ b/__tests__/selector-no-qualifying-type.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with qualifying element', () => { +describe('flags warnings with selector-no-qualifying-type lint', () => { const invalidScss = ( `div#thing { color: #f00; diff --git a/__tests__/selector-no-vendor-prefix.test.mjs b/__tests__/selector-no-vendor-prefix.test.mjs new file mode 100644 index 0000000..219911a --- /dev/null +++ b/__tests__/selector-no-vendor-prefix.test.mjs @@ -0,0 +1,50 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with selector-no-vendor-prefix lint', () => { + const invalidScss = ( +`::-moz-placeholder { + color: #f00; +} + +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected vendor-prefix "::-moz-placeholder" (selector-no-vendor-prefix)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'selector-no-vendor-prefix', + ], + ); + }); +}); diff --git a/__tests__/pseudo-element.test.mjs b/__tests__/selector-pseudo-element-colon-notation.test.mjs similarity index 92% rename from __tests__/pseudo-element.test.mjs rename to __tests__/selector-pseudo-element-colon-notation.test.mjs index 7074963..e0f2a6b 100644 --- a/__tests__/pseudo-element.test.mjs +++ b/__tests__/selector-pseudo-element-colon-notation.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with pseudo-element errors', () => { +describe('flags warnings with selector-pseudo-element-colon-notation lint', () => { const invalidScss = ( `p:before { content: '>'; diff --git a/__tests__/selector-pseudo-element-no-unknown.test.mjs b/__tests__/selector-pseudo-element-no-unknown.test.mjs new file mode 100644 index 0000000..6d3f2c1 --- /dev/null +++ b/__tests__/selector-pseudo-element-no-unknown.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with selector-pseudo-element-no-unknown lint', () => { + const invalidScss = ( +`p::hover { + color: #f00; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected unknown pseudo-element selector "::hover" (selector-pseudo-element-no-unknown)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'selector-pseudo-element-no-unknown', + ], + ); + }); +}); diff --git a/__tests__/shorthand.test.mjs b/__tests__/shorthand-property-no-redundant-values.test.mjs similarity index 91% rename from __tests__/shorthand.test.mjs rename to __tests__/shorthand-property-no-redundant-values.test.mjs index fda60db..2ee1235 100644 --- a/__tests__/shorthand.test.mjs +++ b/__tests__/shorthand-property-no-redundant-values.test.mjs @@ -5,7 +5,7 @@ import stylelint from 'stylelint'; import config from '../index.js'; -describe('flags warnings with shorthand', () => { +describe('flags warnings with shorthand-property-no-redundant-values lint', () => { const invalidScss = ( `.shorthand { margin: 1px 1px 1px 1px; diff --git a/__tests__/string-quotes.test.mjs b/__tests__/string-quotes.test.mjs new file mode 100644 index 0000000..c76de18 --- /dev/null +++ b/__tests__/string-quotes.test.mjs @@ -0,0 +1,51 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with string-quotes lint', () => { + const invalidScss = ( +`.test-selector[data-testid="foo"] { + content: "x"; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 2); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Expected single quotes (@stylistic/string-quotes)', + 'Expected single quotes (@stylistic/string-quotes)' + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + '@stylistic/string-quotes', + '@stylistic/string-quotes' + ], + ); + }); +}); diff --git a/__tests__/value-no-vendor-prefix.test.mjs b/__tests__/value-no-vendor-prefix.test.mjs new file mode 100644 index 0000000..05ceb89 --- /dev/null +++ b/__tests__/value-no-vendor-prefix.test.mjs @@ -0,0 +1,49 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('flags warnings with value-no-vendor-prefix lint', () => { + const invalidScss = ( +`.value-prefix { + display: -webkit-flex; +} +`); + + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: invalidScss, + config, + }); + }); + + it('did error', () => { + assert.equal(result.errored, true); + }); + + it('flags warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('correct warning text', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.text), + [ + 'Unexpected vendor-prefix "-webkit-flex" (value-no-vendor-prefix)', + ], + ); + }); + + it('correct rule flagged', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'value-no-vendor-prefix', + ], + ); + }); +}); diff --git a/__tests__/vendor-prefixes.test.mjs b/__tests__/vendor-prefixes.test.mjs deleted file mode 100644 index ad48da2..0000000 --- a/__tests__/vendor-prefixes.test.mjs +++ /dev/null @@ -1,69 +0,0 @@ -import { beforeEach, describe, it } from 'node:test'; -import assert from 'node:assert/strict'; - -import stylelint from 'stylelint'; - -import config from '../index.js'; - -describe('flags warnings with vendor prefixes', () => { - const invalidScss = ( -`@-webkit-keyframes anim { - 0% { - opacity: 0; - } -} - -::-moz-placeholder { - color: #f00; -} - -.property-prefix { - -webkit-transition: none; -} - -.value-prefix { - display: -webkit-flex; -} -`); - - let result; - - beforeEach(async () => { - result = await stylelint.lint({ - code: invalidScss, - config, - }); - }); - - it('did error', () => { - assert.equal(result.errored, true); - }); - - it('flags warnings', () => { - assert.equal(result.results[0].warnings.length, 4); - }); - - it('correct warning text', () => { - assert.deepEqual( - result.results[0].warnings.map((w) => w.text), - [ - 'Unexpected vendor-prefixed at-rule "@-webkit-keyframes" (at-rule-no-vendor-prefix)', - 'Unexpected vendor-prefix "-webkit-transition" (property-no-vendor-prefix)', - 'Unexpected vendor-prefix "::-moz-placeholder" (selector-no-vendor-prefix)', - 'Unexpected vendor-prefix "-webkit-flex" (value-no-vendor-prefix)', - ], - ); - }); - - it('correct rule flagged', () => { - assert.deepEqual( - result.results[0].warnings.map((w) => w.rule), - [ - 'at-rule-no-vendor-prefix', - 'property-no-vendor-prefix', - 'selector-no-vendor-prefix', - 'value-no-vendor-prefix', - ], - ); - }); -}); diff --git a/index.js b/index.js index f818176..99c2889 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,8 @@ module.exports = { - "plugins": ["stylelint-scss"], + "plugins": [ + "stylelint-scss", + "@stylistic/stylelint-plugin", + ], "customSyntax": "postcss-scss", "rules": { "at-rule-disallowed-list": ["debug"], @@ -40,17 +43,6 @@ module.exports = { "ignore": ["after-comment"] } ], - "scss/at-extend-no-missing-placeholder": true, - "scss/at-function-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", - "scss/at-import-partial-extension-disallowed-list": ["scss"], - "scss/at-rule-no-unknown": true, - "scss/dollar-variable-colon-space-after": "always", - "scss/dollar-variable-colon-space-before": "never", - "scss/dollar-variable-pattern": "^[_]?[a-z]+([a-z0-9-]+[a-z0-9]+)?$", - "scss/load-no-partial-leading-underscore": true, - "scss/no-global-function-names": true, - "scss/percent-placeholder-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", - "scss/selector-no-redundant-nesting-selector": true, "selector-class-pattern": [ "^[a-z0-9\\-]+$", { @@ -65,6 +57,35 @@ module.exports = { "selector-pseudo-element-colon-notation": "double", "selector-pseudo-element-no-unknown": true, "shorthand-property-no-redundant-values": true, - "value-no-vendor-prefix": true + "value-no-vendor-prefix": true, + "@stylistic/block-opening-brace-space-before": "always", + "@stylistic/color-hex-case": "lower", + "@stylistic/declaration-bang-space-after": "never", + "@stylistic/declaration-bang-space-before": "always", + "@stylistic/declaration-block-semicolon-newline-after": "always", + "@stylistic/declaration-block-semicolon-space-before": "never", + "@stylistic/declaration-block-trailing-semicolon": "always", + "@stylistic/declaration-colon-space-after": "always-single-line", + "@stylistic/declaration-colon-space-before": "never", + "@stylistic/function-comma-space-after": "always-single-line", + "@stylistic/function-parentheses-space-inside": "never", + "@stylistic/indentation": 2, + "@stylistic/media-feature-parentheses-space-inside": "never", + "@stylistic/no-missing-end-of-source-newline": true, + "@stylistic/number-leading-zero": "always", + "@stylistic/number-no-trailing-zeros": true, + "@stylistic/selector-list-comma-newline-after": "always", + "@stylistic/string-quotes": "single", + "scss/at-extend-no-missing-placeholder": true, + "scss/at-function-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", + "scss/at-import-partial-extension-disallowed-list": ["scss"], + "scss/at-rule-no-unknown": true, + "scss/dollar-variable-colon-space-after": "always", + "scss/dollar-variable-colon-space-before": "never", + "scss/dollar-variable-pattern": "^[_]?[a-z]+([a-z0-9-]+[a-z0-9]+)?$", + "scss/load-no-partial-leading-underscore": true, + "scss/no-global-function-names": true, + "scss/percent-placeholder-pattern": "^[a-z]+([a-z0-9-]+[a-z0-9]+)?$", + "scss/selector-no-redundant-nesting-selector": true, } } diff --git a/package.json b/package.json index 79fdbf9..b0d7391 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "index.js" ], "dependencies": { + "@stylistic/stylelint-plugin": "^2.1.0", "postcss-scss": "^4.0.9", "stylelint-scss": "^6.2.1" },