ruby_css_lint 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/csslint/CHANGELOG +286 -0
  8. data/csslint/LICENSE +20 -0
  9. data/csslint/README.md +25 -0
  10. data/csslint/build.xml +242 -0
  11. data/csslint/demos/CSSLintDemo.htm +105 -0
  12. data/csslint/demos/demo.css +43 -0
  13. data/csslint/lib/js.jar +0 -0
  14. data/csslint/lib/jshint.js +3963 -0
  15. data/csslint/lib/parserlib.js +6295 -0
  16. data/csslint/lib/yuitest-rhino-cli.js +3955 -0
  17. data/csslint/lib/yuitest.js +4561 -0
  18. data/csslint/npm/package.json +30 -0
  19. data/csslint/release/csslint-node.js +9125 -0
  20. data/csslint/release/csslint-rhino.js +9390 -0
  21. data/csslint/release/csslint-tests.js +1921 -0
  22. data/csslint/release/csslint-worker.js +9148 -0
  23. data/csslint/release/csslint-wsh.js +9477 -0
  24. data/csslint/release/csslint.js +9127 -0
  25. data/csslint/release/npm/cli.js +307 -0
  26. data/csslint/release/npm/lib/csslint-node.js +9125 -0
  27. data/csslint/release/npm/package.json +30 -0
  28. data/csslint/src/cli/common.js +215 -0
  29. data/csslint/src/cli/node.js +87 -0
  30. data/csslint/src/cli/rhino.js +47 -0
  31. data/csslint/src/cli/wsh.js +134 -0
  32. data/csslint/src/core/CSSLint.js +181 -0
  33. data/csslint/src/core/Reporter.js +161 -0
  34. data/csslint/src/core/Util.js +62 -0
  35. data/csslint/src/formatters/checkstyle-xml.js +109 -0
  36. data/csslint/src/formatters/compact.js +59 -0
  37. data/csslint/src/formatters/csslint-xml.js +68 -0
  38. data/csslint/src/formatters/lint-xml.js +69 -0
  39. data/csslint/src/formatters/text.js +64 -0
  40. data/csslint/src/rules/adjoining-classes.js +45 -0
  41. data/csslint/src/rules/box-model.js +93 -0
  42. data/csslint/src/rules/box-sizing.js +28 -0
  43. data/csslint/src/rules/compatible-vendor-prefixes.js +171 -0
  44. data/csslint/src/rules/display-property-grouping.js +117 -0
  45. data/csslint/src/rules/duplicate-background-images.js +37 -0
  46. data/csslint/src/rules/duplicate-properties.js +46 -0
  47. data/csslint/src/rules/empty-rules.js +34 -0
  48. data/csslint/src/rules/errors.js +23 -0
  49. data/csslint/src/rules/fallback-colors.js +67 -0
  50. data/csslint/src/rules/floats.js +36 -0
  51. data/csslint/src/rules/font-faces.js +30 -0
  52. data/csslint/src/rules/font-sizes.js +35 -0
  53. data/csslint/src/rules/gradients.js +69 -0
  54. data/csslint/src/rules/ids.js +50 -0
  55. data/csslint/src/rules/import.js +23 -0
  56. data/csslint/src/rules/important.js +37 -0
  57. data/csslint/src/rules/known-properties.js +29 -0
  58. data/csslint/src/rules/outline-none.js +73 -0
  59. data/csslint/src/rules/overqualified-elements.js +63 -0
  60. data/csslint/src/rules/qualified-headings.js +38 -0
  61. data/csslint/src/rules/regex-selectors.js +44 -0
  62. data/csslint/src/rules/rules-count.js +28 -0
  63. data/csslint/src/rules/shorthand.js +87 -0
  64. data/csslint/src/rules/star-property-hack.js +27 -0
  65. data/csslint/src/rules/text-indent.js +53 -0
  66. data/csslint/src/rules/underscore-property-hack.js +27 -0
  67. data/csslint/src/rules/unique-headings.js +74 -0
  68. data/csslint/src/rules/universal-selector.js +35 -0
  69. data/csslint/src/rules/unqualified-attributes.js +42 -0
  70. data/csslint/src/rules/vendor-prefix.js +143 -0
  71. data/csslint/src/rules/zero-units.js +34 -0
  72. data/csslint/src/worker/Worker.js +26 -0
  73. data/csslint/tests/all-rules.js +64 -0
  74. data/csslint/tests/core/CSSLint.js +22 -0
  75. data/csslint/tests/core/Reporter.js +36 -0
  76. data/csslint/tests/css/width-100.html +76 -0
  77. data/csslint/tests/formatters/checkstyle-xml.js +44 -0
  78. data/csslint/tests/formatters/compact.js +47 -0
  79. data/csslint/tests/formatters/csslint-xml.js +42 -0
  80. data/csslint/tests/formatters/lint-xml.js +43 -0
  81. data/csslint/tests/formatters/text.js +36 -0
  82. data/csslint/tests/rules/adjoining-classes.js +31 -0
  83. data/csslint/tests/rules/box-model.js +211 -0
  84. data/csslint/tests/rules/box-sizing.js +23 -0
  85. data/csslint/tests/rules/compatible-vendor-prefixes.js +56 -0
  86. data/csslint/tests/rules/display-property-grouping.js +213 -0
  87. data/csslint/tests/rules/duplicate-background-images.js +25 -0
  88. data/csslint/tests/rules/duplicate-properties.js +54 -0
  89. data/csslint/tests/rules/empty-rules.js +18 -0
  90. data/csslint/tests/rules/errors.js +17 -0
  91. data/csslint/tests/rules/fallback-colors.js +162 -0
  92. data/csslint/tests/rules/floats.js +35 -0
  93. data/csslint/tests/rules/font-faces.js +28 -0
  94. data/csslint/tests/rules/font-sizes.js +30 -0
  95. data/csslint/tests/rules/gradients.js +60 -0
  96. data/csslint/tests/rules/ids.js +25 -0
  97. data/csslint/tests/rules/import.js +18 -0
  98. data/csslint/tests/rules/important.js +27 -0
  99. data/csslint/tests/rules/known-properties.js +44 -0
  100. data/csslint/tests/rules/outline-none.js +50 -0
  101. data/csslint/tests/rules/overqualified-elements.js +41 -0
  102. data/csslint/tests/rules/qualified-headings.js +19 -0
  103. data/csslint/tests/rules/regex-selectors.js +52 -0
  104. data/csslint/tests/rules/shorthand.js +36 -0
  105. data/csslint/tests/rules/star-property-hack.js +24 -0
  106. data/csslint/tests/rules/text-indent.js +55 -0
  107. data/csslint/tests/rules/underscore-property-hack.js +24 -0
  108. data/csslint/tests/rules/unique-headings.js +47 -0
  109. data/csslint/tests/rules/universal-selector.js +31 -0
  110. data/csslint/tests/rules/unqualified-attributes.js +37 -0
  111. data/csslint/tests/rules/vendor-prefix.js +76 -0
  112. data/csslint/tests/rules/zero-units.js +44 -0
  113. data/csslint/tests/testrunner.htm +138 -0
  114. data/js.jar +0 -0
  115. data/lib/ruby_css_lint.rb +168 -0
  116. data/test/helper.rb +17 -0
  117. data/test/test_ruby_css_lint.rb +7 -0
  118. metadata +240 -0
@@ -0,0 +1,59 @@
1
+ /*global CSSLint*/
2
+ CSSLint.addFormatter({
3
+ //format information
4
+ id: "compact",
5
+ name: "Compact, 'porcelain' format",
6
+
7
+ /**
8
+ * Return content to be printed before all file results.
9
+ * @return {String} to prepend before all results
10
+ */
11
+ startFormat: function() {
12
+ return "";
13
+ },
14
+
15
+ /**
16
+ * Return content to be printed after all file results.
17
+ * @return {String} to append after all results
18
+ */
19
+ endFormat: function() {
20
+ return "";
21
+ },
22
+
23
+ /**
24
+ * Given CSS Lint results for a file, return output for this format.
25
+ * @param results {Object} with error and warning messages
26
+ * @param filename {String} relative file path
27
+ * @param options {Object} (Optional) specifies special handling of output
28
+ * @return {String} output for results
29
+ */
30
+ formatResults: function(results, filename, options) {
31
+ var messages = results.messages,
32
+ output = "";
33
+ options = options || {};
34
+
35
+ /**
36
+ * Capitalize and return given string.
37
+ * @param str {String} to capitalize
38
+ * @return {String} capitalized
39
+ */
40
+ var capitalize = function(str) {
41
+ return str.charAt(0).toUpperCase() + str.slice(1);
42
+ };
43
+
44
+ if (messages.length === 0) {
45
+ return options.quiet ? "" : filename + ": Lint Free!";
46
+ }
47
+
48
+ CSSLint.Util.forEach(messages, function(message, i) {
49
+ if (message.rollup) {
50
+ output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n";
51
+ } else {
52
+ output += filename + ": " + "line " + message.line +
53
+ ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + "\n";
54
+ }
55
+ });
56
+
57
+ return output;
58
+ }
59
+ });
@@ -0,0 +1,68 @@
1
+ /*global CSSLint*/
2
+ CSSLint.addFormatter({
3
+ //format information
4
+ id: "csslint-xml",
5
+ name: "CSSLint XML format",
6
+
7
+ /**
8
+ * Return opening root XML tag.
9
+ * @return {String} to prepend before all results
10
+ */
11
+ startFormat: function(){
12
+ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
13
+ },
14
+
15
+ /**
16
+ * Return closing root XML tag.
17
+ * @return {String} to append after all results
18
+ */
19
+ endFormat: function(){
20
+ return "</csslint>";
21
+ },
22
+
23
+ /**
24
+ * Given CSS Lint results for a file, return output for this format.
25
+ * @param results {Object} with error and warning messages
26
+ * @param filename {String} relative file path
27
+ * @param options {Object} (UNUSED for now) specifies special handling of output
28
+ * @return {String} output for results
29
+ */
30
+ formatResults: function(results, filename, options) {
31
+ var messages = results.messages,
32
+ output = [];
33
+
34
+ /**
35
+ * Replace special characters before write to output.
36
+ *
37
+ * Rules:
38
+ * - single quotes is the escape sequence for double-quotes
39
+ * - &amp; is the escape sequence for &
40
+ * - &lt; is the escape sequence for <
41
+ * - &gt; is the escape sequence for >
42
+ *
43
+ * @param {String} message to escape
44
+ * @return escaped message as {String}
45
+ */
46
+ var escapeSpecialCharacters = function(str) {
47
+ if (!str || str.constructor !== String) {
48
+ return "";
49
+ }
50
+ return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
51
+ };
52
+
53
+ if (messages.length > 0) {
54
+ output.push("<file name=\""+filename+"\">");
55
+ CSSLint.Util.forEach(messages, function (message, i) {
56
+ if (message.rollup) {
57
+ output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
58
+ } else {
59
+ output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
60
+ " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
61
+ }
62
+ });
63
+ output.push("</file>");
64
+ }
65
+
66
+ return output.join("");
67
+ }
68
+ });
@@ -0,0 +1,69 @@
1
+ /*global CSSLint*/
2
+ CSSLint.addFormatter({
3
+ //format information
4
+ id: "lint-xml",
5
+ name: "Lint XML format",
6
+
7
+ /**
8
+ * Return opening root XML tag.
9
+ * @return {String} to prepend before all results
10
+ */
11
+ startFormat: function(){
12
+ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
13
+ },
14
+
15
+ /**
16
+ * Return closing root XML tag.
17
+ * @return {String} to append after all results
18
+ */
19
+ endFormat: function(){
20
+ return "</lint>";
21
+ },
22
+
23
+ /**
24
+ * Given CSS Lint results for a file, return output for this format.
25
+ * @param results {Object} with error and warning messages
26
+ * @param filename {String} relative file path
27
+ * @param options {Object} (UNUSED for now) specifies special handling of output
28
+ * @return {String} output for results
29
+ */
30
+ formatResults: function(results, filename, options) {
31
+ var messages = results.messages,
32
+ output = [];
33
+
34
+ /**
35
+ * Replace special characters before write to output.
36
+ *
37
+ * Rules:
38
+ * - single quotes is the escape sequence for double-quotes
39
+ * - &amp; is the escape sequence for &
40
+ * - &lt; is the escape sequence for <
41
+ * - &gt; is the escape sequence for >
42
+ *
43
+ * @param {String} message to escape
44
+ * @return escaped message as {String}
45
+ */
46
+ var escapeSpecialCharacters = function(str) {
47
+ if (!str || str.constructor !== String) {
48
+ return "";
49
+ }
50
+ return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
51
+ };
52
+
53
+ if (messages.length > 0) {
54
+
55
+ output.push("<file name=\""+filename+"\">");
56
+ CSSLint.Util.forEach(messages, function (message, i) {
57
+ if (message.rollup) {
58
+ output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
59
+ } else {
60
+ output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
61
+ " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
62
+ }
63
+ });
64
+ output.push("</file>");
65
+ }
66
+
67
+ return output.join("");
68
+ }
69
+ });
@@ -0,0 +1,64 @@
1
+ /*global CSSLint*/
2
+ CSSLint.addFormatter({
3
+ //format information
4
+ id: "text",
5
+ name: "Plain Text",
6
+
7
+ /**
8
+ * Return content to be printed before all file results.
9
+ * @return {String} to prepend before all results
10
+ */
11
+ startFormat: function() {
12
+ return "";
13
+ },
14
+
15
+ /**
16
+ * Return content to be printed after all file results.
17
+ * @return {String} to append after all results
18
+ */
19
+ endFormat: function() {
20
+ return "";
21
+ },
22
+
23
+ /**
24
+ * Given CSS Lint results for a file, return output for this format.
25
+ * @param results {Object} with error and warning messages
26
+ * @param filename {String} relative file path
27
+ * @param options {Object} (Optional) specifies special handling of output
28
+ * @return {String} output for results
29
+ */
30
+ formatResults: function(results, filename, options) {
31
+ var messages = results.messages,
32
+ output = "";
33
+ options = options || {};
34
+
35
+ if (messages.length === 0) {
36
+ return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
37
+ }
38
+
39
+ output = "\n\ncsslint: There are " + messages.length + " problems in " + filename + ".";
40
+ var pos = filename.lastIndexOf("/"),
41
+ shortFilename = filename;
42
+
43
+ if (pos === -1){
44
+ pos = filename.lastIndexOf("\\");
45
+ }
46
+ if (pos > -1){
47
+ shortFilename = filename.substring(pos+1);
48
+ }
49
+
50
+ CSSLint.Util.forEach(messages, function (message, i) {
51
+ output = output + "\n\n" + shortFilename;
52
+ if (message.rollup) {
53
+ output += "\n" + (i+1) + ": " + message.type;
54
+ output += "\n" + message.message;
55
+ } else {
56
+ output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
57
+ output += "\n" + message.message;
58
+ output += "\n" + message.evidence;
59
+ }
60
+ });
61
+
62
+ return output;
63
+ }
64
+ });
@@ -0,0 +1,45 @@
1
+ /*global CSSLint*/
2
+ /*
3
+ * Rule: Don't use adjoining classes (.foo.bar).
4
+ */
5
+ CSSLint.addRule({
6
+
7
+ //rule information
8
+ id: "adjoining-classes",
9
+ name: "Disallow adjoining classes",
10
+ desc: "Don't use adjoining classes.",
11
+ browsers: "IE6",
12
+
13
+ //initialization
14
+ init: function(parser, reporter){
15
+ var rule = this;
16
+ parser.addListener("startrule", function(event){
17
+ var selectors = event.selectors,
18
+ selector,
19
+ part,
20
+ modifier,
21
+ classCount,
22
+ i, j, k;
23
+
24
+ for (i=0; i < selectors.length; i++){
25
+ selector = selectors[i];
26
+ for (j=0; j < selector.parts.length; j++){
27
+ part = selector.parts[j];
28
+ if (part.type == parser.SELECTOR_PART_TYPE){
29
+ classCount = 0;
30
+ for (k=0; k < part.modifiers.length; k++){
31
+ modifier = part.modifiers[k];
32
+ if (modifier.type == "class"){
33
+ classCount++;
34
+ }
35
+ if (classCount > 1){
36
+ reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ });
43
+ }
44
+
45
+ });
@@ -0,0 +1,93 @@
1
+ /*global CSSLint*/
2
+
3
+ /*
4
+ * Rule: Don't use width or height when using padding or border.
5
+ */
6
+ CSSLint.addRule({
7
+
8
+ //rule information
9
+ id: "box-model",
10
+ name: "Beware of broken box size",
11
+ desc: "Don't use width or height when using padding or border.",
12
+ browsers: "All",
13
+
14
+ //initialization
15
+ init: function(parser, reporter){
16
+ var rule = this,
17
+ widthProperties = {
18
+ border: 1,
19
+ "border-left": 1,
20
+ "border-right": 1,
21
+ padding: 1,
22
+ "padding-left": 1,
23
+ "padding-right": 1
24
+ },
25
+ heightProperties = {
26
+ border: 1,
27
+ "border-bottom": 1,
28
+ "border-top": 1,
29
+ padding: 1,
30
+ "padding-bottom": 1,
31
+ "padding-top": 1
32
+ },
33
+ properties;
34
+
35
+ function startRule(){
36
+ properties = {};
37
+ }
38
+
39
+ function endRule(){
40
+ var prop;
41
+ if (properties.height){
42
+ for (prop in heightProperties){
43
+ if (heightProperties.hasOwnProperty(prop) && properties[prop]){
44
+
45
+ //special case for padding
46
+ if (!(prop == "padding" && properties[prop].value.parts.length === 2 && properties[prop].value.parts[0].value === 0)){
47
+ reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ if (properties.width){
54
+ for (prop in widthProperties){
55
+ if (widthProperties.hasOwnProperty(prop) && properties[prop]){
56
+
57
+ if (!(prop == "padding" && properties[prop].value.parts.length === 2 && properties[prop].value.parts[1].value === 0)){
58
+ reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ parser.addListener("startrule", startRule);
66
+ parser.addListener("startfontface", startRule);
67
+ parser.addListener("startpage", startRule);
68
+ parser.addListener("startpagemargin", startRule);
69
+ parser.addListener("startkeyframerule", startRule);
70
+
71
+ parser.addListener("property", function(event){
72
+ var name = event.property.text.toLowerCase();
73
+
74
+ if (heightProperties[name] || widthProperties[name]){
75
+ if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
76
+ properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
77
+ }
78
+ } else {
79
+ if (name == "width" || name == "height"){
80
+ properties[name] = 1;
81
+ }
82
+ }
83
+
84
+ });
85
+
86
+ parser.addListener("endrule", endRule);
87
+ parser.addListener("endfontface", endRule);
88
+ parser.addListener("endpage", endRule);
89
+ parser.addListener("endpagemargin", endRule);
90
+ parser.addListener("endkeyframerule", endRule);
91
+ }
92
+
93
+ });
@@ -0,0 +1,28 @@
1
+ /*global CSSLint*/
2
+
3
+ /*
4
+ * Rule: box-sizing doesn't work in IE6 and IE7.
5
+ */
6
+ CSSLint.addRule({
7
+
8
+ //rule information
9
+ id: "box-sizing",
10
+ name: "Disallow use of box-sizing",
11
+ desc: "The box-sizing properties isn't supported in IE6 and IE7.",
12
+ browsers: "IE6, IE7",
13
+ tags: ["Compatibility"],
14
+
15
+ //initialization
16
+ init: function(parser, reporter){
17
+ var rule = this;
18
+
19
+ parser.addListener("property", function(event){
20
+ var name = event.property.text.toLowerCase();
21
+
22
+ if (name == "box-sizing"){
23
+ reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
24
+ }
25
+ });
26
+ }
27
+
28
+ });
@@ -0,0 +1,171 @@
1
+ /*
2
+ * Rule: Include all compatible vendor prefixes to reach a wider
3
+ * range of users.
4
+ */
5
+ /*global CSSLint*/
6
+ CSSLint.addRule({
7
+
8
+ //rule information
9
+ id: "compatible-vendor-prefixes",
10
+ name: "Require compatible vendor prefixes",
11
+ desc: "Include all compatible vendor prefixes to reach a wider range of users.",
12
+ browsers: "All",
13
+
14
+ //initialization
15
+ init: function (parser, reporter) {
16
+ var rule = this,
17
+ compatiblePrefixes,
18
+ properties,
19
+ prop,
20
+ variations,
21
+ prefixed,
22
+ i,
23
+ len,
24
+ arrayPush = Array.prototype.push,
25
+ applyTo = [];
26
+
27
+ // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details
28
+ compatiblePrefixes = {
29
+ "animation" : "webkit moz ms",
30
+ "animation-delay" : "webkit moz ms",
31
+ "animation-direction" : "webkit moz ms",
32
+ "animation-duration" : "webkit moz ms",
33
+ "animation-fill-mode" : "webkit moz ms",
34
+ "animation-iteration-count" : "webkit moz ms",
35
+ "animation-name" : "webkit moz ms",
36
+ "animation-play-state" : "webkit moz ms",
37
+ "animation-timing-function" : "webkit moz ms",
38
+ "appearance" : "webkit moz",
39
+ "border-end" : "webkit moz",
40
+ "border-end-color" : "webkit moz",
41
+ "border-end-style" : "webkit moz",
42
+ "border-end-width" : "webkit moz",
43
+ "border-image" : "webkit moz o",
44
+ "border-radius" : "webkit moz",
45
+ "border-start" : "webkit moz",
46
+ "border-start-color" : "webkit moz",
47
+ "border-start-style" : "webkit moz",
48
+ "border-start-width" : "webkit moz",
49
+ "box-align" : "webkit moz ms",
50
+ "box-direction" : "webkit moz ms",
51
+ "box-flex" : "webkit moz ms",
52
+ "box-lines" : "webkit ms",
53
+ "box-ordinal-group" : "webkit moz ms",
54
+ "box-orient" : "webkit moz ms",
55
+ "box-pack" : "webkit moz ms",
56
+ "box-sizing" : "webkit moz",
57
+ "box-shadow" : "webkit moz",
58
+ "column-count" : "webkit moz ms",
59
+ "column-gap" : "webkit moz ms",
60
+ "column-rule" : "webkit moz ms",
61
+ "column-rule-color" : "webkit moz ms",
62
+ "column-rule-style" : "webkit moz ms",
63
+ "column-rule-width" : "webkit moz ms",
64
+ "column-width" : "webkit moz ms",
65
+ "hyphens" : "epub moz",
66
+ "line-break" : "webkit ms",
67
+ "margin-end" : "webkit moz",
68
+ "margin-start" : "webkit moz",
69
+ "marquee-speed" : "webkit wap",
70
+ "marquee-style" : "webkit wap",
71
+ "padding-end" : "webkit moz",
72
+ "padding-start" : "webkit moz",
73
+ "tab-size" : "moz o",
74
+ "text-size-adjust" : "webkit ms",
75
+ "transform" : "webkit moz ms o",
76
+ "transform-origin" : "webkit moz ms o",
77
+ "transition" : "webkit moz o ms",
78
+ "transition-delay" : "webkit moz o ms",
79
+ "transition-duration" : "webkit moz o ms",
80
+ "transition-property" : "webkit moz o ms",
81
+ "transition-timing-function" : "webkit moz o ms",
82
+ "user-modify" : "webkit moz",
83
+ "user-select" : "webkit moz ms",
84
+ "word-break" : "epub ms",
85
+ "writing-mode" : "epub ms"
86
+ };
87
+
88
+
89
+ for (prop in compatiblePrefixes) {
90
+ if (compatiblePrefixes.hasOwnProperty(prop)) {
91
+ variations = [];
92
+ prefixed = compatiblePrefixes[prop].split(' ');
93
+ for (i = 0, len = prefixed.length; i < len; i++) {
94
+ variations.push('-' + prefixed[i] + '-' + prop);
95
+ }
96
+ compatiblePrefixes[prop] = variations;
97
+ arrayPush.apply(applyTo, variations);
98
+ }
99
+ }
100
+ parser.addListener("startrule", function () {
101
+ properties = [];
102
+ });
103
+
104
+ parser.addListener("property", function (event) {
105
+ var name = event.property;
106
+ if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
107
+ properties.push(name);
108
+ }
109
+ });
110
+
111
+ parser.addListener("endrule", function (event) {
112
+ if (!properties.length) {
113
+ return;
114
+ }
115
+
116
+ var propertyGroups = {},
117
+ i,
118
+ len,
119
+ name,
120
+ prop,
121
+ variations,
122
+ value,
123
+ full,
124
+ actual,
125
+ item,
126
+ propertiesSpecified;
127
+
128
+ for (i = 0, len = properties.length; i < len; i++) {
129
+ name = properties[i];
130
+
131
+ for (prop in compatiblePrefixes) {
132
+ if (compatiblePrefixes.hasOwnProperty(prop)) {
133
+ variations = compatiblePrefixes[prop];
134
+ if (CSSLint.Util.indexOf(variations, name.text) > -1) {
135
+ if (!propertyGroups[prop]) {
136
+ propertyGroups[prop] = {
137
+ full : variations.slice(0),
138
+ actual : [],
139
+ actualNodes: []
140
+ };
141
+ }
142
+ if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
143
+ propertyGroups[prop].actual.push(name.text);
144
+ propertyGroups[prop].actualNodes.push(name);
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+
151
+ for (prop in propertyGroups) {
152
+ if (propertyGroups.hasOwnProperty(prop)) {
153
+ value = propertyGroups[prop];
154
+ full = value.full;
155
+ actual = value.actual;
156
+
157
+ if (full.length > actual.length) {
158
+ for (i = 0, len = full.length; i < len; i++) {
159
+ item = full[i];
160
+ if (CSSLint.Util.indexOf(actual, item) === -1) {
161
+ propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
162
+ reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
163
+ }
164
+ }
165
+
166
+ }
167
+ }
168
+ }
169
+ });
170
+ }
171
+ });