diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..dca543c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,18 @@ +--- +name: Tests +on: + push: + branches: + - 'main' + pull_request: + types: [opened, synchronize, reopened] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v4 + - run: npm ci + - run: npm test + diff --git a/__tests__/index.test.mjs b/__tests__/index.test.mjs new file mode 100644 index 0000000..386cd0d --- /dev/null +++ b/__tests__/index.test.mjs @@ -0,0 +1,72 @@ +import { beforeEach, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; + +import stylelint from 'stylelint'; + +import config from '../index.js'; + +describe('rules', () => { + const ruleNames = Object.keys(config.rules); + + it('is not empty', () => { + assert.ok(ruleNames.length > 0); + }); + + for (const ruleName of ruleNames) { + it(`${ruleName}`, async () => { + const rule = await stylelint.rules[ruleName]; + + assert.ok(!rule.meta.deprecated, `the ${ruleName} rule is deprecated`); + }); + } +}) + +describe('with the valid example', () => { + const sampleScss = fs.readFileSync('./__tests__/valid.scss', 'utf-8'); + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: sampleScss, + config, + }); + }); + + it('does not error', () => { + assert.equal(result.errored, false); + }); + + it('has no warnings', () => { + assert.equal(result.results[0].warnings.length, 0); + }); +}); + +describe('with the invalid example', () => { + const sampleScss = fs.readFileSync('./__tests__/invalid.scss', 'utf-8'); + let result; + + beforeEach(async () => { + result = await stylelint.lint({ + code: sampleScss, + config, + }); + }); + + it('do error', () => { + assert.equal(result.errored, true); + }); + + it('has the correct amount of warnings', () => { + assert.equal(result.results[0].warnings.length, 1); + }); + + it('flags the correct rules', () => { + assert.deepEqual( + result.results[0].warnings.map((w) => w.rule), + [ + 'color-hex-length', + ], + ); + }); +}); diff --git a/__tests__/invalid.scss b/__tests__/invalid.scss new file mode 100644 index 0000000..8e49582 --- /dev/null +++ b/__tests__/invalid.scss @@ -0,0 +1 @@ +$color-variable: #fff; diff --git a/__tests__/valid.scss b/__tests__/valid.scss new file mode 100644 index 0000000..bed75a2 --- /dev/null +++ b/__tests__/valid.scss @@ -0,0 +1,51 @@ +@import "partial-name"; + +$color-variable: #ffffff; + +/* I'm here to explain what this class does */ +.class-one { + background-color: $color-variable; + border: 0; + line-height: 1.5; + text-size: 0.5rem; + transition: background-color 0.5s ease; + + @media (width >= 1px) { + margin: ($spacing-variable * 2) 1rem; + } + + &:hover { + box-shadow: 0 0 2px 1px rgba($color-variable, 0.2); + } + + &::before { + content: "hello"; + } +} + +$map: ( + "key-1": value-1, + "key-2": value-2, +); + +.class-two { + @extend %placeholder; + @include mixin; + + align-items: center; + display: flex; + flex: 1 1 auto; + + a { + text-decoration: none; + + &:focus, + &:hover { + text-decoration: underline; + } + } + + &.child { + color: $red; + } +} diff --git a/index.js b/index.js index ac7b515..c14892a 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,8 @@ module.exports = { - "extends": "stylelint-config-recommended", + "extends": ["stylelint-config-standard-scss", "stylelint-config-recommended"], "plugins": [ "stylelint-declaration-block-no-ignored-properties", "stylelint-order", - "stylelint-scss" ], "rules": { "at-rule-no-unknown": null, diff --git a/package-lock.json b/package-lock.json index a600191..4ff79fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,9 @@ "license": "MIT", "dependencies": { "stylelint-config-recommended": "^13.0.0", + "stylelint-config-standard-scss": "^11.0.0", "stylelint-declaration-block-no-ignored-properties": "^2.5.0", - "stylelint-order": "^6.0.0", - "stylelint-scss": "^5.0.0" + "stylelint-order": "^6.0.0" }, "peerDependencies": { "stylelint": "^15.10.1" @@ -1132,9 +1132,9 @@ "peer": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -1286,9 +1286,9 @@ } }, "node_modules/postcss": { - "version": "8.4.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", - "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", @@ -1304,7 +1304,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -1338,6 +1338,31 @@ "postcss": "^8.3.3" } }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, "node_modules/postcss-selector-parser": { "version": "6.0.13", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", @@ -1763,6 +1788,57 @@ "stylelint": "^15.10.0" } }, + "node_modules/stylelint-config-recommended-scss": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-13.1.0.tgz", + "integrity": "sha512-8L5nDfd+YH6AOoBGKmhH8pLWF1dpfY816JtGMePcBqqSsLU+Ysawx44fQSlMOJ2xTfI9yTGpup5JU77c17w1Ww==", + "dependencies": { + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^13.0.0", + "stylelint-scss": "^5.3.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^15.10.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, + "node_modules/stylelint-config-standard": { + "version": "34.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-34.0.0.tgz", + "integrity": "sha512-u0VSZnVyW9VSryBG2LSO+OQTjN7zF9XJaAJRX/4EwkmU0R2jYwmBSN10acqZisDitS0CLiEiGjX7+Hrq8TAhfQ==", + "dependencies": { + "stylelint-config-recommended": "^13.0.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "stylelint": "^15.10.0" + } + }, + "node_modules/stylelint-config-standard-scss": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-11.0.0.tgz", + "integrity": "sha512-fGE79NBOLg09a9afqGH/guJulRULCaQWWv4cv1v2bMX92B+fGb0y56WqIguwvFcliPmmUXiAhKrrnXilIeXoHA==", + "dependencies": { + "stylelint-config-recommended-scss": "^13.0.0", + "stylelint-config-standard": "^34.0.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^15.10.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, "node_modules/stylelint-declaration-block-no-ignored-properties": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/stylelint-declaration-block-no-ignored-properties/-/stylelint-declaration-block-no-ignored-properties-2.7.0.tgz", @@ -1787,10 +1863,11 @@ } }, "node_modules/stylelint-scss": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-5.0.1.tgz", - "integrity": "sha512-n87iCRZrr2J7//I/QFsDXxFLnHKw633U4qvWZ+mOW6KDAp/HLj06H+6+f9zOuTYy+MdGdTuCSDROCpQIhw5fvQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-5.3.2.tgz", + "integrity": "sha512-4LzLaayFhFyneJwLo0IUa8knuIvj+zF0vBFueQs4e3tEaAMIQX8q5th8ziKkgOavr6y/y9yoBe+RXN/edwLzsQ==", "dependencies": { + "known-css-properties": "^0.29.0", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-selector-parser": "^6.0.13", @@ -1800,6 +1877,11 @@ "stylelint": "^14.5.1 || ^15.0.0" } }, + "node_modules/stylelint-scss/node_modules/known-css-properties": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2796,9 +2878,9 @@ "peer": true }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, "normalize-package-data": { "version": "3.0.3", @@ -2896,11 +2978,11 @@ "peer": true }, "postcss": { - "version": "8.4.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", - "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "requires": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -2922,6 +3004,12 @@ "peer": true, "requires": {} }, + "postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "requires": {} + }, "postcss-selector-parser": { "version": "6.0.13", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", @@ -3213,6 +3301,33 @@ "integrity": "sha512-EH+yRj6h3GAe/fRiyaoO2F9l9Tgg50AOFhaszyfov9v6ayXJ1IkSHwTxd7lB48FmOeSGDPLjatjO11fJpmarkQ==", "requires": {} }, + "stylelint-config-recommended-scss": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-13.1.0.tgz", + "integrity": "sha512-8L5nDfd+YH6AOoBGKmhH8pLWF1dpfY816JtGMePcBqqSsLU+Ysawx44fQSlMOJ2xTfI9yTGpup5JU77c17w1Ww==", + "requires": { + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^13.0.0", + "stylelint-scss": "^5.3.0" + } + }, + "stylelint-config-standard": { + "version": "34.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-34.0.0.tgz", + "integrity": "sha512-u0VSZnVyW9VSryBG2LSO+OQTjN7zF9XJaAJRX/4EwkmU0R2jYwmBSN10acqZisDitS0CLiEiGjX7+Hrq8TAhfQ==", + "requires": { + "stylelint-config-recommended": "^13.0.0" + } + }, + "stylelint-config-standard-scss": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-11.0.0.tgz", + "integrity": "sha512-fGE79NBOLg09a9afqGH/guJulRULCaQWWv4cv1v2bMX92B+fGb0y56WqIguwvFcliPmmUXiAhKrrnXilIeXoHA==", + "requires": { + "stylelint-config-recommended-scss": "^13.0.0", + "stylelint-config-standard": "^34.0.0" + } + }, "stylelint-declaration-block-no-ignored-properties": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/stylelint-declaration-block-no-ignored-properties/-/stylelint-declaration-block-no-ignored-properties-2.7.0.tgz", @@ -3229,14 +3344,22 @@ } }, "stylelint-scss": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-5.0.1.tgz", - "integrity": "sha512-n87iCRZrr2J7//I/QFsDXxFLnHKw633U4qvWZ+mOW6KDAp/HLj06H+6+f9zOuTYy+MdGdTuCSDROCpQIhw5fvQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-5.3.2.tgz", + "integrity": "sha512-4LzLaayFhFyneJwLo0IUa8knuIvj+zF0vBFueQs4e3tEaAMIQX8q5th8ziKkgOavr6y/y9yoBe+RXN/edwLzsQ==", "requires": { + "known-css-properties": "^0.29.0", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-selector-parser": "^6.0.13", "postcss-value-parser": "^4.2.0" + }, + "dependencies": { + "known-css-properties": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==" + } } }, "supports-color": { diff --git a/package.json b/package.json index 24e2827..94177cb 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "author": "thoughtbot, Inc.", "dependencies": { "stylelint-config-recommended": "^13.0.0", + "stylelint-config-standard-scss": "^11.0.0", "stylelint-declaration-block-no-ignored-properties": "^2.5.0", - "stylelint-order": "^6.0.0", - "stylelint-scss": "^5.0.0" + "stylelint-order": "^6.0.0" }, "keywords": [ "stylelint", @@ -21,6 +21,8 @@ "url": "https://github.com/thoughtbot/stylelint-config.git" }, "scripts": { + "test": "node --test __tests__/*.test.*", + "lint": "stylelint", "prepublishOnly": "git push && git push --tags", "version": "git add CHANGELOG.md" },