sasslint 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 (46) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +29 -0
  4. data/bin/sasslint +6 -0
  5. data/lib/sasslint.rb +10 -0
  6. data/lib/sasslint/cli.rb +28 -0
  7. data/lib/sasslint/helpers/path_helper.rb +10 -0
  8. data/lib/sasslint/helpers/rule_importer.rb +25 -0
  9. data/lib/sasslint/rules/css/adjoining-classes.rb +52 -0
  10. data/lib/sasslint/rules/css/box-model.rb +108 -0
  11. data/lib/sasslint/rules/css/box-sizing.rb +35 -0
  12. data/lib/sasslint/rules/css/bulletproof-font-face.rb +73 -0
  13. data/lib/sasslint/rules/css/compatible-vendor-prefixes.rb +193 -0
  14. data/lib/sasslint/rules/css/display-property-grouping.rb +124 -0
  15. data/lib/sasslint/rules/css/duplicate-background-images.rb +44 -0
  16. data/lib/sasslint/rules/css/duplicate-properties.rb +53 -0
  17. data/lib/sasslint/rules/css/empty-rules.rb +41 -0
  18. data/lib/sasslint/rules/css/errors.rb +30 -0
  19. data/lib/sasslint/rules/css/fallback-colors.rb +84 -0
  20. data/lib/sasslint/rules/css/floats.rb +43 -0
  21. data/lib/sasslint/rules/css/font-faces.rb +37 -0
  22. data/lib/sasslint/rules/css/font-sizes.rb +42 -0
  23. data/lib/sasslint/rules/css/gradients.rb +71 -0
  24. data/lib/sasslint/rules/css/ids.rb +57 -0
  25. data/lib/sasslint/rules/css/import.rb +30 -0
  26. data/lib/sasslint/rules/css/important.rb +44 -0
  27. data/lib/sasslint/rules/css/known-properties.rb +36 -0
  28. data/lib/sasslint/rules/css/outline-none.rb +80 -0
  29. data/lib/sasslint/rules/css/overqualified-elements.rb +70 -0
  30. data/lib/sasslint/rules/css/qualified-headings.rb +45 -0
  31. data/lib/sasslint/rules/css/regex-selectors.rb +51 -0
  32. data/lib/sasslint/rules/css/rules-count.rb +35 -0
  33. data/lib/sasslint/rules/css/selector-max-approaching.rb +35 -0
  34. data/lib/sasslint/rules/css/selector-max.rb +35 -0
  35. data/lib/sasslint/rules/css/shorthand.rb +94 -0
  36. data/lib/sasslint/rules/css/star-property-hack.rb +34 -0
  37. data/lib/sasslint/rules/css/text-indent.rb +60 -0
  38. data/lib/sasslint/rules/css/underscore-property-hack.rb +34 -0
  39. data/lib/sasslint/rules/css/unique-headings.rb +81 -0
  40. data/lib/sasslint/rules/css/universal-selector.rb +42 -0
  41. data/lib/sasslint/rules/css/unqualified-attributes.rb +49 -0
  42. data/lib/sasslint/rules/css/vendor-prefix.rb +150 -0
  43. data/lib/sasslint/rules/css/zero-units.rb +41 -0
  44. data/lib/sasslint/version.rb +3 -0
  45. data/sasslint.gemspec +29 -0
  46. metadata +146 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NWNiM2VmNjQ4MWU4ODY4ZjIxYTU3MTNmMjdkNzI1ZTI5OTI5ODQ3OA==
5
+ data.tar.gz: !binary |-
6
+ Yzc2MGIzZjU5MmExMjgxZGFkNmNjNWU2YjJkYjZmYzhjYzMxN2QzMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YWRkNTU1ZmE5Mjg0MWVhZTFkM2Q0MDc5OTA5ZjY0MDM5Y2NiMGU2OGZkOTUx
10
+ NjM3YjM0ZDFhOThhZWEzMDVjYTYyNmVlMDFkODRkOGU0NGE2ZDkyNTA4ZTIz
11
+ MzkwOGY3YmM1MDk0MmY3ZmIyMWFmYjQ5MjBmNDEzYmIyYjUzN2I=
12
+ data.tar.gz: !binary |-
13
+ NmUyYzY4MzQ1MDNjODg1Zjk4NjI4N2ZlMmY5OTI3MzM2YTNjMGQ2ZjE1MmYy
14
+ MjNmODdlYzNlODIwZDdmOTRiODBlNTZhNjc2NzcxMGJhMTY1ZmU4NjNiY2Q1
15
+ NGY1NjRlZjU2ZmVjOWE3ODRkNTk0MmIwZmY3MGRlZjY2YjA3MTU=
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Roman Stranghoener
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # SassLint
2
+
3
+ A linter for Sass, based on the idea and concepts of [csslint](https://github.com/stubbornella/csslint).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'taste'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install taste
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ require 'sasslint/cli'
6
+ SassLint::CLI.start
@@ -0,0 +1,10 @@
1
+ require 'active_support/all'
2
+
3
+ module SassLint
4
+ def self.gem_root
5
+ @gem_root ||= File.expand_path("../..", __FILE__)
6
+ end
7
+ end
8
+
9
+ require "sasslint/version"
10
+ require "sasslint/helpers/rule_importer"
@@ -0,0 +1,28 @@
1
+ require 'thor'
2
+ require 'sasslint'
3
+
4
+ module SassLint
5
+ class CLI < Thor
6
+
7
+ desc "check", "runs the Sass linter"
8
+
9
+ # Provide CSSLint global CLI Options
10
+ method_option :format, desc: "Indicate which format to use for output."
11
+ method_option :listrules, desc: "Outputs all of the rules available."
12
+ method_option :quiet, desc: "Only output when errors are present."
13
+ method_option :errors, desc: "Indicate which rules to include as errors."
14
+ method_option :warnings, desc: "Indicate which rules to include as warnings."
15
+ method_option :ignore, desc: "Indicate which rules to ignore completely."
16
+ method_option :exclude, desc: "Indicate which files/directories to exclude from being linted."
17
+ method_option :version, desc: "Outputs the current version number."
18
+ def check
19
+ puts "TODO: linting that shit"
20
+ end
21
+
22
+ desc "import", "imports CSSLint rules"
23
+ def import
24
+ puts "Importing CSSLint rules"
25
+ RuleImporter.import
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ module SassLint
2
+ module Helper
3
+ module PathHelper
4
+ extend ActiveSupport::Concern
5
+
6
+ # Path helper methods go here
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ require 'sasslint'
2
+
3
+ module RuleImporter
4
+ def self.import
5
+ target_dir = File.join(SassLint.gem_root, 'lib', 'sasslint', 'rules', 'css')
6
+ input_files = File.join(SassLint.gem_root, 'lib', 'sasslint', 'rules', 'js', '*.js')
7
+
8
+ Dir.glob(input_files) do |js_file|
9
+ rb_file_name = "#{File.basename(js_file, '.*')}.rb"
10
+ rb_file = File.new(File.join(target_dir, rb_file_name), 'w+')
11
+ rb_file.puts "\# This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules"
12
+ rb_file.puts "\#"
13
+ rb_file.puts "\#"
14
+ rb_file.puts "\# Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved."
15
+ rb_file.puts "\# TODO: Paste the CSSLint LICENSE here."
16
+ rb_file.puts "\#"
17
+ rb_file.puts "\#"
18
+ File.open(js_file).each do |line|
19
+ rb_file.puts "\# #{line}"
20
+ end
21
+
22
+ rb_file.close
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ # This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules
2
+ #
3
+ #
4
+ # Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
5
+ # TODO: Paste the CSSLint LICENSE here.
6
+ #
7
+ #
8
+ # /*global CSSLint*/
9
+ # /*
10
+ # * Rule: Don't use adjoining classes (.foo.bar).
11
+ # */
12
+ # CSSLint.addRule({
13
+ #
14
+ # //rule information
15
+ # id: "adjoining-classes",
16
+ # name: "Disallow adjoining classes",
17
+ # desc: "Don't use adjoining classes.",
18
+ # browsers: "IE6",
19
+ #
20
+ # //initialization
21
+ # init: function(parser, reporter){
22
+ # var rule = this;
23
+ # parser.addListener("startrule", function(event){
24
+ # var selectors = event.selectors,
25
+ # selector,
26
+ # part,
27
+ # modifier,
28
+ # classCount,
29
+ # i, j, k;
30
+ #
31
+ # for (i=0; i < selectors.length; i++){
32
+ # selector = selectors[i];
33
+ # for (j=0; j < selector.parts.length; j++){
34
+ # part = selector.parts[j];
35
+ # if (part.type == parser.SELECTOR_PART_TYPE){
36
+ # classCount = 0;
37
+ # for (k=0; k < part.modifiers.length; k++){
38
+ # modifier = part.modifiers[k];
39
+ # if (modifier.type == "class"){
40
+ # classCount++;
41
+ # }
42
+ # if (classCount > 1){
43
+ # reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
44
+ # }
45
+ # }
46
+ # }
47
+ # }
48
+ # }
49
+ # });
50
+ # }
51
+ #
52
+ # });
@@ -0,0 +1,108 @@
1
+ # This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules
2
+ #
3
+ #
4
+ # Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
5
+ # TODO: Paste the CSSLint LICENSE here.
6
+ #
7
+ #
8
+ # /*global CSSLint*/
9
+ #
10
+ # /*
11
+ # * Rule: Don't use width or height when using padding or border.
12
+ # */
13
+ # CSSLint.addRule({
14
+ #
15
+ # //rule information
16
+ # id: "box-model",
17
+ # name: "Beware of broken box size",
18
+ # desc: "Don't use width or height when using padding or border.",
19
+ # browsers: "All",
20
+ #
21
+ # //initialization
22
+ # init: function(parser, reporter){
23
+ # var rule = this,
24
+ # widthProperties = {
25
+ # border: 1,
26
+ # "border-left": 1,
27
+ # "border-right": 1,
28
+ # padding: 1,
29
+ # "padding-left": 1,
30
+ # "padding-right": 1
31
+ # },
32
+ # heightProperties = {
33
+ # border: 1,
34
+ # "border-bottom": 1,
35
+ # "border-top": 1,
36
+ # padding: 1,
37
+ # "padding-bottom": 1,
38
+ # "padding-top": 1
39
+ # },
40
+ # properties,
41
+ # boxSizing = false;
42
+ #
43
+ # function startRule(){
44
+ # properties = {};
45
+ # boxSizing = false;
46
+ # }
47
+ #
48
+ # function endRule(){
49
+ # var prop, value;
50
+ #
51
+ # if (!boxSizing) {
52
+ # if (properties.height){
53
+ # for (prop in heightProperties){
54
+ # if (heightProperties.hasOwnProperty(prop) && properties[prop]){
55
+ # value = properties[prop].value;
56
+ # //special case for padding
57
+ # if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
58
+ # reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
59
+ # }
60
+ # }
61
+ # }
62
+ # }
63
+ #
64
+ # if (properties.width){
65
+ # for (prop in widthProperties){
66
+ # if (widthProperties.hasOwnProperty(prop) && properties[prop]){
67
+ # value = properties[prop].value;
68
+ #
69
+ # if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
70
+ # reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
71
+ # }
72
+ # }
73
+ # }
74
+ # }
75
+ # }
76
+ # }
77
+ #
78
+ # parser.addListener("startrule", startRule);
79
+ # parser.addListener("startfontface", startRule);
80
+ # parser.addListener("startpage", startRule);
81
+ # parser.addListener("startpagemargin", startRule);
82
+ # parser.addListener("startkeyframerule", startRule);
83
+ #
84
+ # parser.addListener("property", function(event){
85
+ # var name = event.property.text.toLowerCase();
86
+ #
87
+ # if (heightProperties[name] || widthProperties[name]){
88
+ # if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
89
+ # properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
90
+ # }
91
+ # } else {
92
+ # if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
93
+ # properties[name] = 1;
94
+ # } else if (name == "box-sizing") {
95
+ # boxSizing = true;
96
+ # }
97
+ # }
98
+ #
99
+ # });
100
+ #
101
+ # parser.addListener("endrule", endRule);
102
+ # parser.addListener("endfontface", endRule);
103
+ # parser.addListener("endpage", endRule);
104
+ # parser.addListener("endpagemargin", endRule);
105
+ # parser.addListener("endkeyframerule", endRule);
106
+ # }
107
+ #
108
+ # });
@@ -0,0 +1,35 @@
1
+ # This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules
2
+ #
3
+ #
4
+ # Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
5
+ # TODO: Paste the CSSLint LICENSE here.
6
+ #
7
+ #
8
+ # /*global CSSLint*/
9
+ #
10
+ # /*
11
+ # * Rule: box-sizing doesn't work in IE6 and IE7.
12
+ # */
13
+ # CSSLint.addRule({
14
+ #
15
+ # //rule information
16
+ # id: "box-sizing",
17
+ # name: "Disallow use of box-sizing",
18
+ # desc: "The box-sizing properties isn't supported in IE6 and IE7.",
19
+ # browsers: "IE6, IE7",
20
+ # tags: ["Compatibility"],
21
+ #
22
+ # //initialization
23
+ # init: function(parser, reporter){
24
+ # var rule = this;
25
+ #
26
+ # parser.addListener("property", function(event){
27
+ # var name = event.property.text.toLowerCase();
28
+ #
29
+ # if (name == "box-sizing"){
30
+ # reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
31
+ # }
32
+ # });
33
+ # }
34
+ #
35
+ # });
@@ -0,0 +1,73 @@
1
+ # This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules
2
+ #
3
+ #
4
+ # Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
5
+ # TODO: Paste the CSSLint LICENSE here.
6
+ #
7
+ #
8
+ # /*
9
+ # * Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE
10
+ # * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)
11
+ # */
12
+ # /*global CSSLint*/
13
+ # CSSLint.addRule({
14
+ #
15
+ # //rule information
16
+ # id: "bulletproof-font-face",
17
+ # name: "Use the bulletproof @font-face syntax",
18
+ # desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",
19
+ # browsers: "All",
20
+ #
21
+ # //initialization
22
+ # init: function(parser, reporter){
23
+ # var rule = this,
24
+ # count = 0,
25
+ # fontFaceRule = false,
26
+ # firstSrc = true,
27
+ # ruleFailed = false,
28
+ # line, col;
29
+ #
30
+ # // Mark the start of a @font-face declaration so we only test properties inside it
31
+ # parser.addListener("startfontface", function(event){
32
+ # fontFaceRule = true;
33
+ # });
34
+ #
35
+ # parser.addListener("property", function(event){
36
+ # // If we aren't inside an @font-face declaration then just return
37
+ # if (!fontFaceRule) {
38
+ # return;
39
+ # }
40
+ #
41
+ # var propertyName = event.property.toString().toLowerCase(),
42
+ # value = event.value.toString();
43
+ #
44
+ # // Set the line and col numbers for use in the endfontface listener
45
+ # line = event.line;
46
+ # col = event.col;
47
+ #
48
+ # // This is the property that we care about, we can ignore the rest
49
+ # if (propertyName === 'src') {
50
+ # var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
51
+ #
52
+ # // We need to handle the advanced syntax with two src properties
53
+ # if (!value.match(regex) && firstSrc) {
54
+ # ruleFailed = true;
55
+ # firstSrc = false;
56
+ # } else if (value.match(regex) && !firstSrc) {
57
+ # ruleFailed = false;
58
+ # }
59
+ # }
60
+ #
61
+ #
62
+ # });
63
+ #
64
+ # // Back to normal rules that we don't need to test
65
+ # parser.addListener("endfontface", function(event){
66
+ # fontFaceRule = false;
67
+ #
68
+ # if (ruleFailed) {
69
+ # reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
70
+ # }
71
+ # });
72
+ # }
73
+ # });
@@ -0,0 +1,193 @@
1
+ # This rule is taken from https://github.com/stubbornella/csslint/tree/master/src/rules
2
+ #
3
+ #
4
+ # Copyright (c) 2011 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
5
+ # TODO: Paste the CSSLint LICENSE here.
6
+ #
7
+ #
8
+ # /*
9
+ # * Rule: Include all compatible vendor prefixes to reach a wider
10
+ # * range of users.
11
+ # */
12
+ # /*global CSSLint*/
13
+ # CSSLint.addRule({
14
+ #
15
+ # //rule information
16
+ # id: "compatible-vendor-prefixes",
17
+ # name: "Require compatible vendor prefixes",
18
+ # desc: "Include all compatible vendor prefixes to reach a wider range of users.",
19
+ # browsers: "All",
20
+ #
21
+ # //initialization
22
+ # init: function (parser, reporter) {
23
+ # var rule = this,
24
+ # compatiblePrefixes,
25
+ # properties,
26
+ # prop,
27
+ # variations,
28
+ # prefixed,
29
+ # i,
30
+ # len,
31
+ # inKeyFrame = false,
32
+ # arrayPush = Array.prototype.push,
33
+ # applyTo = [];
34
+ #
35
+ # // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details
36
+ # compatiblePrefixes = {
37
+ # "animation" : "webkit moz",
38
+ # "animation-delay" : "webkit moz",
39
+ # "animation-direction" : "webkit moz",
40
+ # "animation-duration" : "webkit moz",
41
+ # "animation-fill-mode" : "webkit moz",
42
+ # "animation-iteration-count" : "webkit moz",
43
+ # "animation-name" : "webkit moz",
44
+ # "animation-play-state" : "webkit moz",
45
+ # "animation-timing-function" : "webkit moz",
46
+ # "appearance" : "webkit moz",
47
+ # "border-end" : "webkit moz",
48
+ # "border-end-color" : "webkit moz",
49
+ # "border-end-style" : "webkit moz",
50
+ # "border-end-width" : "webkit moz",
51
+ # "border-image" : "webkit moz o",
52
+ # "border-radius" : "webkit",
53
+ # "border-start" : "webkit moz",
54
+ # "border-start-color" : "webkit moz",
55
+ # "border-start-style" : "webkit moz",
56
+ # "border-start-width" : "webkit moz",
57
+ # "box-align" : "webkit moz ms",
58
+ # "box-direction" : "webkit moz ms",
59
+ # "box-flex" : "webkit moz ms",
60
+ # "box-lines" : "webkit ms",
61
+ # "box-ordinal-group" : "webkit moz ms",
62
+ # "box-orient" : "webkit moz ms",
63
+ # "box-pack" : "webkit moz ms",
64
+ # "box-sizing" : "webkit moz",
65
+ # "box-shadow" : "webkit moz",
66
+ # "column-count" : "webkit moz ms",
67
+ # "column-gap" : "webkit moz ms",
68
+ # "column-rule" : "webkit moz ms",
69
+ # "column-rule-color" : "webkit moz ms",
70
+ # "column-rule-style" : "webkit moz ms",
71
+ # "column-rule-width" : "webkit moz ms",
72
+ # "column-width" : "webkit moz ms",
73
+ # "hyphens" : "epub moz",
74
+ # "line-break" : "webkit ms",
75
+ # "margin-end" : "webkit moz",
76
+ # "margin-start" : "webkit moz",
77
+ # "marquee-speed" : "webkit wap",
78
+ # "marquee-style" : "webkit wap",
79
+ # "padding-end" : "webkit moz",
80
+ # "padding-start" : "webkit moz",
81
+ # "tab-size" : "moz o",
82
+ # "text-size-adjust" : "webkit ms",
83
+ # "transform" : "webkit moz ms o",
84
+ # "transform-origin" : "webkit moz ms o",
85
+ # "transition" : "webkit moz o",
86
+ # "transition-delay" : "webkit moz o",
87
+ # "transition-duration" : "webkit moz o",
88
+ # "transition-property" : "webkit moz o",
89
+ # "transition-timing-function" : "webkit moz o",
90
+ # "user-modify" : "webkit moz",
91
+ # "user-select" : "webkit moz ms",
92
+ # "word-break" : "epub ms",
93
+ # "writing-mode" : "epub ms"
94
+ # };
95
+ #
96
+ #
97
+ # for (prop in compatiblePrefixes) {
98
+ # if (compatiblePrefixes.hasOwnProperty(prop)) {
99
+ # variations = [];
100
+ # prefixed = compatiblePrefixes[prop].split(' ');
101
+ # for (i = 0, len = prefixed.length; i < len; i++) {
102
+ # variations.push('-' + prefixed[i] + '-' + prop);
103
+ # }
104
+ # compatiblePrefixes[prop] = variations;
105
+ # arrayPush.apply(applyTo, variations);
106
+ # }
107
+ # }
108
+ #
109
+ # parser.addListener("startrule", function () {
110
+ # properties = [];
111
+ # });
112
+ #
113
+ # parser.addListener("startkeyframes", function (event) {
114
+ # inKeyFrame = event.prefix || true;
115
+ # });
116
+ #
117
+ # parser.addListener("endkeyframes", function (event) {
118
+ # inKeyFrame = false;
119
+ # });
120
+ #
121
+ # parser.addListener("property", function (event) {
122
+ # var name = event.property;
123
+ # if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
124
+ #
125
+ # // e.g., -moz-transform is okay to be alone in @-moz-keyframes
126
+ # if (!inKeyFrame || typeof inKeyFrame != "string" ||
127
+ # name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
128
+ # properties.push(name);
129
+ # }
130
+ # }
131
+ # });
132
+ #
133
+ # parser.addListener("endrule", function (event) {
134
+ # if (!properties.length) {
135
+ # return;
136
+ # }
137
+ #
138
+ # var propertyGroups = {},
139
+ # i,
140
+ # len,
141
+ # name,
142
+ # prop,
143
+ # variations,
144
+ # value,
145
+ # full,
146
+ # actual,
147
+ # item,
148
+ # propertiesSpecified;
149
+ #
150
+ # for (i = 0, len = properties.length; i < len; i++) {
151
+ # name = properties[i];
152
+ #
153
+ # for (prop in compatiblePrefixes) {
154
+ # if (compatiblePrefixes.hasOwnProperty(prop)) {
155
+ # variations = compatiblePrefixes[prop];
156
+ # if (CSSLint.Util.indexOf(variations, name.text) > -1) {
157
+ # if (!propertyGroups[prop]) {
158
+ # propertyGroups[prop] = {
159
+ # full : variations.slice(0),
160
+ # actual : [],
161
+ # actualNodes: []
162
+ # };
163
+ # }
164
+ # if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
165
+ # propertyGroups[prop].actual.push(name.text);
166
+ # propertyGroups[prop].actualNodes.push(name);
167
+ # }
168
+ # }
169
+ # }
170
+ # }
171
+ # }
172
+ #
173
+ # for (prop in propertyGroups) {
174
+ # if (propertyGroups.hasOwnProperty(prop)) {
175
+ # value = propertyGroups[prop];
176
+ # full = value.full;
177
+ # actual = value.actual;
178
+ #
179
+ # if (full.length > actual.length) {
180
+ # for (i = 0, len = full.length; i < len; i++) {
181
+ # item = full[i];
182
+ # if (CSSLint.Util.indexOf(actual, item) === -1) {
183
+ # propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
184
+ # reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
185
+ # }
186
+ # }
187
+ #
188
+ # }
189
+ # }
190
+ # }
191
+ # });
192
+ # }
193
+ # });