ruby_css_lint 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ });