├── README.md ├── package.json ├── test └── index.js ├── lib └── dictionary.js └── index.js /README.md: -------------------------------------------------------------------------------- 1 | # css-mixed-properties 2 | 3 | Lints CSS rulesets for mixing structure and skin properties 4 | 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-mixed-properties", 3 | "version": "1.1.0", 4 | "description": "Lints CSS rulesets for mixing structure and skin property types", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha test" 8 | }, 9 | "author": "Brent Jackson", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "basscss": "^5.0.1", 13 | "cssnext": "^1.1.0", 14 | "mocha": "^2.2.1" 15 | }, 16 | "dependencies": { 17 | "lodash": "^3.5.0", 18 | "postcss": "^4.1.10" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var mocha = require('mocha'); 3 | var assert = require('assert'); 4 | var mixedProperties = require('..'); 5 | var cssnext = require('cssnext'); 6 | 7 | var basscss = cssnext('@import "basscss"'); 8 | var results = mixedProperties(basscss); 9 | 10 | describe('css-mixed-properties', function() { 11 | 12 | it('should do something', function() { 13 | assert.notEqual(typeof results, 'undefined'); 14 | }); 15 | 16 | it('should have rules', function() { 17 | assert(results.rules); 18 | }); 19 | 20 | it('should have warnings', function() { 21 | assert(results.warnings); 22 | }); 23 | 24 | it('should produce scores', function() { 25 | results.rules.forEach(function(rule) { 26 | assert.equal(typeof rule.score, 'number'); 27 | }); 28 | }); 29 | 30 | }); 31 | 32 | -------------------------------------------------------------------------------- /lib/dictionary.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | structure: [ 4 | 'font', 5 | 'font-size', 6 | 'line-height', 7 | 'box-sizing', 8 | 'margin', 9 | 'margin-top', 10 | 'margin-right', 11 | 'margin-bottom', 12 | 'margin-left', 13 | 'padding', 14 | 'padding-top', 15 | 'padding-right', 16 | 'padding-bottom', 17 | 'padding-left', 18 | 'width', 19 | 'min-width', 20 | 'max-width', 21 | 'height', 22 | 'min-height', 23 | 'max-height', 24 | 'display', 25 | 'float', 26 | 'clear', 27 | 'position', 28 | 'top', 29 | 'right', 30 | 'bottom', 31 | 'left', 32 | 'z-index', 33 | 'vertical-align', 34 | 'table-layout', 35 | ], 36 | skin: [ 37 | 'color', 38 | 'background', 39 | 'background-color', 40 | 'background-size', 41 | 'background-repeat', 42 | 'background-image', 43 | 'border', 44 | 'border-style', 45 | 'border-color', 46 | 'border-top', 47 | 'border-top-style', 48 | 'border-top-color', 49 | 'border-right', 50 | 'border-right-style', 51 | 'border-right-color', 52 | 'border-bottom', 53 | 'border-bottom-style', 54 | 'border-bottom-color', 55 | 'border-left', 56 | 'border-left-style', 57 | 'border-left-color', 58 | 'border-radius', 59 | 'border-top-left-radius', 60 | 'border-top-right-radius', 61 | 'border-bottom-right-radius', 62 | 'border-bottom-left-radius', 63 | 'box-shadow', 64 | 'text-shadow', 65 | 'opacity', 66 | ] 67 | }; 68 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var _ = require('lodash'); 3 | var postcss = require('postcss'); 4 | var dictionary = require('./lib/dictionary'); 5 | 6 | module.exports = function(css, options) { 7 | 8 | var options = options || {}; 9 | options = _.defaults(options, { 10 | safe: true 11 | }); 12 | 13 | var root = postcss.parse(css, options); 14 | 15 | var results = {}; 16 | results.rules = []; 17 | results.warnings = []; 18 | 19 | root.eachRule(function(rule) { 20 | var x = 0; 21 | var y = 0; 22 | var ratio = 0; 23 | var score = 0; 24 | var properties = []; 25 | 26 | rule.eachDecl(function(decl) { 27 | properties.push(decl.prop); 28 | }); 29 | 30 | properties.forEach(function(prop) { 31 | if (_.indexOf(dictionary.structure, prop) !== -1) { 32 | x++; 33 | } else if (_.indexOf(dictionary.skin, prop) !== -1) { 34 | y++; 35 | } 36 | }); 37 | 38 | ratio = (x > y) ? y/x : x/y || 0; 39 | score = ratio * properties.length; 40 | 41 | results.rules.push({ 42 | selector: rule.selector, 43 | line: rule.source.start.line, 44 | declarations: { 45 | total: properties.length, 46 | structure: x, 47 | skin: y 48 | }, 49 | ratio: ratio, 50 | score: score 51 | }); 52 | 53 | if (score > 6) { 54 | results.warnings.push({ 55 | selector: rule.selector, 56 | line: rule.source.start.line, 57 | message: 'Ruleset has a high mix of property types and a high number of declarations', 58 | ratio: ratio, 59 | score: score, 60 | }); 61 | } else if (ratio > .5) { 62 | results.warnings.push({ 63 | selector: rule.selector, 64 | line: rule.source.start.line, 65 | message: 'Ruleset has a high mix of property types', 66 | ratio: ratio, 67 | score: score, 68 | }); 69 | } 70 | 71 | }); 72 | 73 | return results; 74 | }; 75 | 76 | --------------------------------------------------------------------------------