├── .gitignore ├── README.md ├── package.json └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stylelint-group-selectors 2 | Identify the selectors, which can be grouped, as they have same set of properties and values. 3 | 4 | 5 | ```css 6 | .a{ display: inline-block;width: 100px;} 7 | .b{display:inline-block;width:100px;} 8 | 9 | ``` 10 | Above selectors can be grouped like this 11 | ```css 12 | .a,.b{display:inline-block;width: 100px;} 13 | ``` 14 | ## Installation 15 | 16 | ``` 17 | npm install stylelint-group-selectors --save-dev 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```js 23 | // .stylelintrc 24 | { 25 | "plugins": [ 26 | "stylelint-group-selectors" 27 | ], 28 | "rules": { 29 | "plugin/stylelint-group-selectors": true, 30 | } 31 | } 32 | ``` 33 | ## Options 34 | 35 | ### `true` 36 | 37 | The following patterns are considered violations: 38 | ```css 39 | .b{display:inline-block;color:#111;} 40 | .a{display:inline-block;color:#111;} 41 | ``` 42 | ```css 43 | .a,.b{display: inline-block;color:#111; } 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-group-selectors", 3 | "version": "1.0.8", 4 | "description": "stylelint plugin to identify the selectors can be grouped as they have same set of properties and values", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": { 10 | "name": "Sivantarajan", 11 | "url": "https://github.com/ssivanatarajan/" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/ssivanatarajan/stylelint-group-selectors/issues" 15 | }, 16 | "license": "MIT", 17 | "dependencies": { 18 | "postcss": "^8.4.14", 19 | "md5": "2.3.0" 20 | }, 21 | "peerDependencies": { 22 | "stylelint": ">=14.9.1" 23 | }, 24 | "homepage": "https://github.com/ssivanatarajan/stylelint-group-selectors/blob/master/README.md", 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/ssivanatarajan/stylelint-group-selectors.git" 28 | }, 29 | "keywords": [ 30 | "stylelint", 31 | "stylelint-plugin", 32 | "css", 33 | "sass", 34 | "scss", 35 | "Group Selectors" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var stylelint = require("stylelint"); 2 | var md5 = require('md5'); 3 | var ruleName = "plugin/stylelint-group-selectors"; 4 | 5 | 6 | var messages = stylelint.utils.ruleMessages(ruleName, { 7 | expected: function(selector1, selector2) { 8 | return '" ' + selector1 + ' " and ' + selector2 + " have same properties, group them." 9 | } 10 | }); 11 | 12 | module.exports = stylelint.createPlugin(ruleName, function(enabled) { 13 | if (!enabled) { 14 | return; 15 | } 16 | return function(root, result) { 17 | 18 | var selectorGroups = []; 19 | root.walkRules(rule => { 20 | var selector = rule.selector; 21 | if (rule != undefined && rule.parent != undefined && rule.parent.type != "rule" && rule.parent.type != 'atrule' && (!(selector.includes('-webkit-') || selector.includes('-moz-') || selector.includes('-o-') || selector.includes('-ms-')))) { 22 | var cssContent = ""; 23 | var hashValue = 0; 24 | var cssArray = []; 25 | rule.nodes.forEach(function(property) { 26 | if (property.type == "decl") { 27 | var prop = property.prop; 28 | var value = property.value; 29 | var propval = ""; 30 | if (property != undefined && value != undefined) { 31 | if (property.important) 32 | propval = prop + value + "!important"; 33 | else 34 | propval = prop + value; 35 | cssArray.push(propval); 36 | } 37 | } 38 | }) 39 | 40 | cssArray = cssArray.sort(); 41 | cssContent = cssArray.toString(); 42 | if (cssContent.trim().length > 0) { 43 | hashValue = md5(cssContent); 44 | var selectorWithlineNO = selector + "(" + rule.source.start.line + ":" + rule.source.start.column + ")"; 45 | var selObj = selectorGroups[hashValue] 46 | if (selObj) { 47 | if (selectorGroups[hashValue].selectors.indexOf(selector) == -1) { 48 | 49 | var lastSelector = selectorGroups[hashValue].selectors[selectorGroups[hashValue].selectors.length - 1]; 50 | stylelint.utils.report({ 51 | result, 52 | ruleName, 53 | message: messages.expected(selector, lastSelector), 54 | node: rule, 55 | word: rule.node 56 | }); 57 | selectorGroups[hashValue].selectors.push(selector); 58 | } 59 | } else { 60 | var Obj = {}; 61 | Obj.selectors = []; 62 | Obj.selectors.push(selectorWithlineNO); 63 | selectorGroups[hashValue] = Obj 64 | } 65 | } 66 | } 67 | }); 68 | } 69 | }); 70 | module.exports.ruleName = ruleName; 71 | module.exports.messages = messages; --------------------------------------------------------------------------------