diff --git a/notes.md b/notes.md new file mode 100644 index 00000000..abaa2500 --- /dev/null +++ b/notes.md @@ -0,0 +1,6 @@ +Steps to run dev version of csslint from the command line (not the current release): + +1. command line: "ant" +1. edit /build/npm/package.json give it a version number like 1.0.0 +1. command line: "npm link" (in the build/npm dir, possibly sudo) +1. command line: "csslint " \ No newline at end of file diff --git a/src/rules/duplicate-property-count.js b/src/rules/duplicate-property-count.js new file mode 100644 index 00000000..cc4b2ea4 --- /dev/null +++ b/src/rules/duplicate-property-count.js @@ -0,0 +1,54 @@ +/* + * Rule: Be aware of duplicate property-value pairs. + */ +/*global CSSLint*/ +CSSLint.addRule({ + + //rule information + id: "duplicate-property-count", + name: "Duplicate properties", + desc: "Be aware of duplicate properties. Many duplicates may indicate the need for abstratcion.", + browsers: "All", + + //initialization + init: function(parser, reporter){ + var rule = this; + var count = {}; + + //count how many times "float" is used + parser.addListener("property", function(event){ + var prop = event.property.text.toLowerCase(), + val = event.value.text.toLowerCase(), + key = prop + ':' + val; + + if (!count[prop]) { + count[prop] = 0; + } + + count[prop] += 1; + }); + + //report the results + parser.addListener("endstylesheet", function(){ + var data = [], + msg = []; // remove + + for (var prop in count) { + if (count.hasOwnProperty(prop)) { + data.push([prop, count[prop]]); + } + } + + data.sort(function (a, b) { + return b[1] - a[1]; + }); + + data = data.map(function (item) { + return item[1] + ',' + item[0]; + }).join('\n'); + + reporter.rollupWarn('Duplicate property count:\n\n' + data); + }); + } + +}); diff --git a/src/rules/duplicate-property-value-pairs.js b/src/rules/duplicate-property-value-pairs.js new file mode 100644 index 00000000..7ff63469 --- /dev/null +++ b/src/rules/duplicate-property-value-pairs.js @@ -0,0 +1,54 @@ +/* + * Rule: Be aware of duplicate property-value pairs. + */ +/*global CSSLint*/ +CSSLint.addRule({ + + //rule information + id: "duplicate-property-value-pairs", + name: "Duplicate property-value pairs", + desc: "Be aware of duplicate property-value pairs. Many duplicates may indicate the need for abstratcion.", + browsers: "All", + + //initialization + init: function(parser, reporter){ + var rule = this; + var count = {}; + + //count how many times "float" is used + parser.addListener("property", function(event){ + var prop = event.property.text.toLowerCase(), + val = event.value.text.toLowerCase(), + key = prop + '|' + val; + + if (!count[key]) { + count[key] = 0; + } + + count[key] += 1; + }); + + //report the results + parser.addListener("endstylesheet", function(){ + var data = [], + msg = []; + + for (var prop in count) { + if (count.hasOwnProperty(prop)) { + data.push([prop, count[prop]]); + } + } + + data.sort(function (a, b) { + return b[1] - a[1]; + }); + + data = data.map(function (item) { + return item[1] + '|' + item[0]; + }).join('\n'); + + reporter.rollupWarn('Duplicate property-value-pairs:\n\n' + data); + }); + } + +}); diff --git a/src/rules/non-link-hover b/src/rules/non-link-hover new file mode 100644 index 00000000..a6575264 --- /dev/null +++ b/src/rules/non-link-hover @@ -0,0 +1,40 @@ +/* + * Rule: When using a :hover selector ensure that it has been anchored with the tag. + */ +/*global CSSLint*/ +CSSLint.addRule({ + + //rule information + id: "non-link-hover", + name: "Non-Link Hover", + desc: "Using :hover pseudo-selector to non-link elements is known to be slow.", + browsers: "IE7, IE8", + + //initialization + init: function(parser, reporter){ + var rule = this; + + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + modifier, + i, j, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + + part = selector.parts[selector.parts.length-1]; + + if (part.modifiers.length-1 !== -1){ + if (part.modifiers[part.modifiers.length-1].text === ":hover" && (part.elementName == null || (part.elementName != "a" && part.elementName != "A"))){ + reporter.warn(rule.desc, part.line, part.col, rule); + } + } + + } + }); + } + +}); diff --git a/src/rules/rules-count.js b/src/rules/rules-count.js index b7712ff2..072b5839 100644 --- a/src/rules/rules-count.js +++ b/src/rules/rules-count.js @@ -21,7 +21,8 @@ CSSLint.addRule({ }); parser.addListener("endstylesheet", function(){ - reporter.stat("rule-count", count); + reporter.stat("rules-count", count); + reporter.rollupWarn('This CSS contains ' + count + ' rules.'); }); } diff --git a/tests/rules/duplicate-property-count.js b/tests/rules/duplicate-property-count.js new file mode 100644 index 00000000..592725c9 --- /dev/null +++ b/tests/rules/duplicate-property-count.js @@ -0,0 +1,18 @@ +(function(){ + + /*global YUITest, CSSLint*/ + var Assert = YUITest.Assert; + + YUITest.TestRunner.add(new YUITest.TestCase({ + + name: "Duplicate Property-Value Pair Rule Errors", + + "Duplicate property count should result in a warning": function () { + var result = CSSLint.verify(".foo { color: #f00; } .bar { color: #f00; }", {"duplicate-property-count": 1}); + Assert.areEqual(1, result.messages.length); + Assert.areEqual("warning", result.messages[0].type); + Assert.areEqual("Duplicate property count:\n\n2,color", result.messages[0].message); + } + })); + +})(); diff --git a/tests/rules/duplicate-property-value-pairs.js b/tests/rules/duplicate-property-value-pairs.js new file mode 100644 index 00000000..505a173f --- /dev/null +++ b/tests/rules/duplicate-property-value-pairs.js @@ -0,0 +1,18 @@ +(function(){ + + /*global YUITest, CSSLint*/ + var Assert = YUITest.Assert; + + YUITest.TestRunner.add(new YUITest.TestCase({ + + name: "Duplicate Property-Value Pair Rule Errors", + + "Duplicate property-value pairs should result in a warning": function () { + var result = CSSLint.verify(".foo { color: #f00; } .bar { color: #f00; }", {"duplicate-property-value-pairs": 1}); + Assert.areEqual(1, result.messages.length); + Assert.areEqual("warning", result.messages[0].type); + Assert.areEqual("Duplicate property-value-pairs:\n\n2|color|#f00", result.messages[0].message); + } + })); + +})(); diff --git a/tests/rules/non-link-hover.js b/tests/rules/non-link-hover.js new file mode 100644 index 00000000..31676b8f --- /dev/null +++ b/tests/rules/non-link-hover.js @@ -0,0 +1,19 @@ +(function(){ + + /*global YUITest, CSSLint*/ + var Assert = YUITest.Assert; + + YUITest.TestRunner.add(new YUITest.TestCase({ + name: ":hover; Warning", + "using :hover on non-link ements should result in an warning": function(){ + var result = CSSLint.verify("li:hover {color:blue;} .foo:hover {float:left;} #foo:hover {clear:both;} div.faa :hover {font-size:1px;}, body .test-result .tmp-program .test-program-left .test-program-title .test-program-help-image :hover, body .test-eligibility-result.cw-collapsed-map .test-eligibility-triage .test-top-panel-left-image:hover, body .test-eligibility-result .test-eligibility-result-triage .test-panel-right-image :hover {font-size:1px;}, body .test-eligibility-result .test-eligibility-result-triage .test-panel-image:hover {background-position: 100% 49%;}", { "non-link-hover": 4 }); + Assert.areEqual(4, result.messages.length); + Assert.areEqual("warn", result.messages[0].type); + Assert.areEqual("Using :hover pseudo-selector to non-link elements is known to be slow.", result.messages[0].message); + }, + "using :hover on link ements should not result in any remark": function(){ + var result = CSSLint.verify("a:hover {color:red;} li a:hover, div a:hover {color:red;}, body .test-result .tmp-program .test-program-left .test-program-title .test-program-help-image a:hover, body .test-eligibility-result.cw-collapsed-map .test-eligibility-triage a.test-top-panel-left-image:hover, body .test-eligibility-result .test-eligibility-result-triage .test-panel-right-image a:hover {font-size:1px;}, body .test-eligibility-result .test-eligibility-result-triage a.test-panel-image:hover {background-position: 100% 49%;}", { "non-link-hover": 0 }); + Assert.areEqual(0, result.messages.length); + } + })); +})(); \ No newline at end of file diff --git a/tests/rules/rules-count.js b/tests/rules/rules-count.js new file mode 100644 index 00000000..7cb4bd72 --- /dev/null +++ b/tests/rules/rules-count.js @@ -0,0 +1,20 @@ +(function(){ + + /*global YUITest, CSSLint*/ + var Assert = YUITest.Assert; + + YUITest.TestRunner.add(new YUITest.TestCase({ + + name: "Rule Count Errors", + + "Rules should be counted": function(){ + var result = CSSLint.verify("h1 { color:#fff; }.foo{color: red;}", { "rules-count": 1}); + // console.dir(result); + Assert.areEqual(1, result.messages.length); + Assert.areEqual("warning", result.messages[0].type); + Assert.areEqual("This CSS contains 2 rules.", result.messages[0].message); + } + + })); + +})();