Skip to content
This repository
Browse code

Version 0.9.8

  • Loading branch information...
commit 2a2cac5748d4371a1b3a05883e89bcf311e0ef25 1 parent ee1af4e
Nicholas C. Zakas authored May 14, 2012
27  CHANGELOG
... ...
@@ -1,3 +1,28 @@
  1
+May 14, 2012 - v0.9.8
  2
+
  3
+* Merge pull request #272 from mahonnaise/text-indent (Nicholas C. Zakas)
  4
+* Changed the -98px test to -99px (the exact threshold value). Added -99em and -100em tests in order to increase test coverage and to document the current (actually desired) behavior (see #133). (Jos Hirth)
  5
+* Ensure proper output flushing for Node.js (Nicholas C. Zakas)
  6
+* Fix output for checkstyle when a file can't be read (fixes #253) (Nicholas C. Zakas)
  7
+* Merge branch 'master' of github.com:stubbornella/csslint (Nicholas C. Zakas)
  8
+* Updated parser (fixes #261, fixes #259, fixes #242) (Nicholas C. Zakas)
  9
+* Merge pull request #269 from mahonnaise/master (Nicholas C. Zakas)
  10
+* Merge pull request #270 from huangyingjie/master (Nicholas C. Zakas)
  11
+* cannot find csslint.js (huangyingjie)
  12
+* use the parser's "hack" property instead of redoing this step again (Jos Hirth)
  13
+* +2 rules which detected star (IE6/7) and underscore (IE6) property hacks (Jos Hirth)
  14
+* Merge pull request #268 from frvge/patch-1 (Nicholas C. Zakas)
  15
+* Fix typo (Frank van Gemeren)
  16
+* Merge pull request #265 from frvge/patch-1 (Nicholas C. Zakas)
  17
+* Fix typo (Frank van Gemeren)
  18
+* Merge pull request #252 from aaronpowell/master (Nicholas C. Zakas)
  19
+* Merge pull request #260 from mahonnaise/master (Nicholas C. Zakas)
  20
+* use separate flags for text-indent and direction. fixes #249 (Jos Hirth)
  21
+* Merge pull request #256 from khoomeister/master (Nicholas C. Zakas)
  22
+* updated xml formatters to escape ampersand character, updated tests to check ampersand and fixed other tests to check angled brackets as well (Jenkins)
  23
+* Update npm/package.json (Aaron Powell)
  24
+
  25
+
1 26
 March 2, 2012 - v0.9.7
2 27
 
3 28
 * Fix unqualified attribute issue (fixes #237) (Nicholas C. Zakas)
@@ -257,3 +282,5 @@ June 15, 2011 - v0.1.0
257 282
 
258 283
 
259 284
 
  285
+
  286
+
2  build.xml
... ...
@@ -1,7 +1,7 @@
1 1
 <project name="csslint" default="build.all">
2 2
 
3 3
     <!-- version number -->
4  
-    <property name="csslint.version" value="0.9.7" />
  4
+    <property name="csslint.version" value="0.9.8" />
5 5
 
6 6
     <!-- the directories containing the source files -->
7 7
     <property name="src.dir" value="./src" />
290  release/csslint-node.js
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 21
 THE SOFTWARE.
22 22
 
23 23
 */
24  
-/* Build time: 2-March-2012 02:47:11 */
  24
+/* Build time: 14-May-2012 10:24:48 */
25 25
 
26 26
 /*!
27 27
 Parser-Lib
@@ -46,7 +46,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 46
 THE SOFTWARE.
47 47
 
48 48
 */
49  
-/* Version v0.1.6, Build time: 2-March-2012 02:44:32 */
  49
+/* Version v0.1.7, Build time: 4-May-2012 03:57:04 */
50 50
 var parserlib = {};
51 51
 (function(){
52 52
 
@@ -956,7 +956,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
956 956
 THE SOFTWARE.
957 957
 
958 958
 */
959  
-/* Version v0.1.6, Build time: 2-March-2012 02:44:32 */
  959
+/* Version v0.1.7, Build time: 4-May-2012 03:57:04 */
960 960
 (function(){
961 961
 var EventTarget = parserlib.util.EventTarget,
962 962
 TokenStreamBase = parserlib.util.TokenStreamBase,
@@ -2665,7 +2665,8 @@ Parser.prototype = function(){
2665 2665
                     expr        = null,
2666 2666
                     prio        = null,
2667 2667
                     error       = null,
2668  
-                    invalid     = null;
  2668
+                    invalid     = null,
  2669
+                    propertyName= "";
2669 2670
                 
2670 2671
                 property = this._property();
2671 2672
                 if (property !== null){
@@ -2682,8 +2683,20 @@ Parser.prototype = function(){
2682 2683
                     
2683 2684
                     prio = this._prio();
2684 2685
                     
  2686
+                    /*
  2687
+                     * If hacks should be allowed, then only check the root
  2688
+                     * property. If hacks should not be allowed, treat
  2689
+                     * _property or *property as invalid properties.
  2690
+                     */
  2691
+                    propertyName = property.toString();
  2692
+                    if (this.options.starHack && property.hack == "*" ||
  2693
+                            this.options.underscoreHack && property.hack == "_") {
  2694
+                         
  2695
+                        propertyName = property.text;
  2696
+                    }
  2697
+                    
2685 2698
                     try {
2686  
-                        this._validateProperty(property, expr);
  2699
+                        this._validateProperty(propertyName, expr);
2687 2700
                     } catch (ex) {
2688 2701
                         invalid = ex;
2689 2702
                     }
@@ -3524,6 +3537,7 @@ var Properties = {
3524 3537
     "background-repeat"             : { multi: "<repeat-style>" },
3525 3538
     "background-size"               : { multi: "<bg-size>", comma: true },
3526 3539
     "baseline-shift"                : "baseline | sub | super | <percentage> | <length>",
  3540
+    "behavior"                      : 1,
3527 3541
     "binding"                       : 1,
3528 3542
     "bleed"                         : "<length>",
3529 3543
     "bookmark-label"                : "<content> | <attr> | <string>",
@@ -3870,6 +3884,7 @@ var Properties = {
3870 3884
     "text-justify"                  : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
3871 3885
     "text-outline"                  : 1,
3872 3886
     "text-overflow"                 : 1,
  3887
+    "text-rendering"                : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
3873 3888
     "text-shadow"                   : 1,
3874 3889
     "text-transform"                : "capitalize | uppercase | lowercase | none | inherit",
3875 3890
     "text-wrap"                     : "normal | none | avoid",
@@ -5949,7 +5964,7 @@ var ValidationTypes = {
5949 5964
             i, len, found = false;
5950 5965
         
5951 5966
         for (i=0,len=args.length; i < len && !found; i++){
5952  
-            if (text == args[i]){
  5967
+            if (text == args[i].toLowerCase()){
5953 5968
                 found = true;
5954 5969
             }
5955 5970
         }
@@ -6041,7 +6056,7 @@ var ValidationTypes = {
6041 6056
         },        
6042 6057
         
6043 6058
         "<gradient>": function(part) {
6044  
-            return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial|linear)\-gradient/i.test(part);
  6059
+            return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
6045 6060
         },
6046 6061
         
6047 6062
         "<box>": function(part){
@@ -6133,6 +6148,18 @@ var ValidationTypes = {
6133 6148
                 part,
6134 6149
                 i, len;
6135 6150
             
  6151
+/*
  6152
+<position> = [
  6153
+  [ left | center | right | top | bottom | <percentage> | <length> ]
  6154
+|
  6155
+  [ left | center | right | <percentage> | <length> ]
  6156
+  [ top | center | bottom | <percentage> | <length> ]
  6157
+|
  6158
+  [ center | [ left | right ] [ <percentage> | <length> ]? ] &&
  6159
+  [ center | [ top | bottom ] [ <percentage> | <length> ]? ]
  6160
+]
  6161
+
  6162
+*/            
6136 6163
                 
6137 6164
             if (ValidationTypes.isAny(expression, "top | bottom")) {
6138 6165
                 result = true;
@@ -6305,7 +6332,7 @@ var CSSLint = (function(){
6305 6332
         formatters = [],
6306 6333
         api        = new parserlib.util.EventTarget();
6307 6334
         
6308  
-    api.version = "0.9.7";
  6335
+    api.version = "0.9.8";
6309 6336
 
6310 6337
     //-------------------------------------------------------------------------
6311 6338
     // Rule Management
@@ -7632,7 +7659,7 @@ CSSLint.addRule({
7632 7659
         parser.addListener("endstylesheet", function(){
7633 7660
             reporter.stat("important", count);
7634 7661
             if (count >= 10){
7635  
-                reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specifity issues.", rule);
  7662
+                reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
7636 7663
             }
7637 7664
         });
7638 7665
     }
@@ -8289,8 +8316,35 @@ CSSLint.addRule({
8289 8316
 
8290 8317
 });
8291 8318
 /*
8292  
- * Rule: Don't use text-indent for image replacement if you need to support rtl. 
8293  
- * 
  8319
+ * Rule: Don't use properties with a star prefix.
  8320
+ *
  8321
+ */
  8322
+/*global CSSLint*/
  8323
+CSSLint.addRule({
  8324
+
  8325
+    //rule information
  8326
+    id: "star-property-hack",
  8327
+    name: "Disallow properties with a star prefix",
  8328
+    desc: "Checks for the star property hack (targets IE6/7)",
  8329
+    browsers: "All",
  8330
+
  8331
+    //initialization
  8332
+    init: function(parser, reporter){
  8333
+        var rule = this;
  8334
+
  8335
+        //check if property name starts with "*"
  8336
+        parser.addListener("property", function(event){
  8337
+            var property = event.property;
  8338
+
  8339
+            if (property.hack == "*") {
  8340
+                reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
  8341
+            }
  8342
+        });
  8343
+    }
  8344
+});
  8345
+/*
  8346
+ * Rule: Don't use text-indent for image replacement if you need to support rtl.
  8347
+ *
8294 8348
  */
8295 8349
 /*global CSSLint*/
8296 8350
 CSSLint.addRule({
@@ -8300,27 +8354,29 @@ CSSLint.addRule({
8300 8354
     name: "Disallow negative text-indent",
8301 8355
     desc: "Checks for text indent less than -99px",
8302 8356
     browsers: "All",
8303  
-    
  8357
+
8304 8358
     //initialization
8305 8359
     init: function(parser, reporter){
8306 8360
         var rule = this,
8307  
-            textIndent = false;
8308  
-            
8309  
-            
  8361
+            textIndent,
  8362
+            direction;
  8363
+
  8364
+
8310 8365
         function startRule(event){
8311 8366
             textIndent = false;
  8367
+            direction = "inherit";
8312 8368
         }
8313  
-        
  8369
+
8314 8370
         //event handler for end of rules
8315 8371
         function endRule(event){
8316  
-            if (textIndent){
  8372
+            if (textIndent && direction != "ltr"){
8317 8373
                 reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule);
8318 8374
             }
8319  
-        }        
8320  
-        
  8375
+        }
  8376
+
8321 8377
         parser.addListener("startrule", startRule);
8322 8378
         parser.addListener("startfontface", startRule);
8323  
-    
  8379
+
8324 8380
         //check for use of "font-size"
8325 8381
         parser.addListener("property", function(event){
8326 8382
             var name = event.property.toString().toLowerCase(),
@@ -8329,17 +8385,44 @@ CSSLint.addRule({
8329 8385
             if (name == "text-indent" && value.parts[0].value < -99){
8330 8386
                 textIndent = event.property;
8331 8387
             } else if (name == "direction" && value == "ltr"){
8332  
-                textIndent = false;
  8388
+                direction = "ltr";
8333 8389
             }
8334 8390
         });
8335 8391
 
8336 8392
         parser.addListener("endrule", endRule);
8337  
-        parser.addListener("endfontface", endRule);     
  8393
+        parser.addListener("endfontface", endRule);
8338 8394
 
8339 8395
     }
8340 8396
 
8341 8397
 });
8342 8398
 /*
  8399
+ * Rule: Don't use properties with a underscore prefix.
  8400
+ *
  8401
+ */
  8402
+/*global CSSLint*/
  8403
+CSSLint.addRule({
  8404
+
  8405
+    //rule information
  8406
+    id: "underscore-property-hack",
  8407
+    name: "Disallow properties with an underscore prefix",
  8408
+    desc: "Checks for the underscore property hack (targets IE6)",
  8409
+    browsers: "All",
  8410
+
  8411
+    //initialization
  8412
+    init: function(parser, reporter){
  8413
+        var rule = this;
  8414
+
  8415
+        //check if property name starts with "_"
  8416
+        parser.addListener("property", function(event){
  8417
+            var property = event.property;
  8418
+
  8419
+            if (property.hack == "_") {
  8420
+                reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
  8421
+            }
  8422
+        });
  8423
+    }
  8424
+});
  8425
+/*
8343 8426
  * Rule: Headings (h1-h6) should be defined only once.
8344 8427
  */
8345 8428
 /*global CSSLint*/
@@ -8668,85 +8751,114 @@ CSSLint.addRule({
8668 8751
 
8669 8752
 });
8670 8753
 /*global CSSLint*/
8671  
-CSSLint.addFormatter({
8672  
-    //format information
8673  
-    id: "checkstyle-xml",
8674  
-    name: "Checkstyle XML format",
  8754
+(function() {
8675 8755
 
8676 8756
     /**
8677  
-     * Return opening root XML tag.
8678  
-     * @return {String} to prepend before all results
  8757
+     * Replace special characters before write to output.
  8758
+     *
  8759
+     * Rules:
  8760
+     *  - single quotes is the escape sequence for double-quotes
  8761
+     *  - &amp; is the escape sequence for &
  8762
+     *  - &lt; is the escape sequence for <
  8763
+     *  - &gt; is the escape sequence for >
  8764
+     *
  8765
+     * @param {String} message to escape
  8766
+     * @return escaped message as {String}
8679 8767
      */
8680  
-    startFormat: function(){
8681  
-        return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
8682  
-    },
  8768
+    var xmlEscape = function(str) {
  8769
+        if (!str || str.constructor !== String) {
  8770
+            return "";
  8771
+        }
  8772
+        
  8773
+        return str.replace(/[\"&><]/g, function(match) {
  8774
+            switch (match) {
  8775
+                case "\"":
  8776
+                    return "&quot;";
  8777
+                case "&":
  8778
+                    return "&amp;";
  8779
+                case "<":
  8780
+                    return "&lt;";
  8781
+                case ">":
  8782
+                    return "&gt;";            
  8783
+            }
  8784
+        });
  8785
+    };
8683 8786
 
8684  
-    /**
8685  
-     * Return closing root XML tag.
8686  
-     * @return {String} to append after all results
8687  
-     */
8688  
-    endFormat: function(){
8689  
-        return "</checkstyle>";
8690  
-    },
  8787
+    CSSLint.addFormatter({
  8788
+        //format information
  8789
+        id: "checkstyle-xml",
  8790
+        name: "Checkstyle XML format",
8691 8791
 
8692  
-    /**
8693  
-     * Given CSS Lint results for a file, return output for this format.
8694  
-     * @param results {Object} with error and warning messages
8695  
-     * @param filename {String} relative file path
8696  
-     * @param options {Object} (UNUSED for now) specifies special handling of output
8697  
-     * @return {String} output for results
8698  
-     */
8699  
-    formatResults: function(results, filename, options) {
8700  
-        var messages = results.messages,
8701  
-            output = [];
  8792
+        /**
  8793
+         * Return opening root XML tag.
  8794
+         * @return {String} to prepend before all results
  8795
+         */
  8796
+        startFormat: function(){
  8797
+            return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
  8798
+        },
8702 8799
 
8703 8800
         /**
8704  
-         * Generate a source string for a rule.
8705  
-         * Checkstyle source strings usually resemble Java class names e.g
8706  
-         * net.csslint.SomeRuleName
8707  
-         * @param {Object} rule
8708  
-         * @return rule source as {String}
  8801
+         * Return closing root XML tag.
  8802
+         * @return {String} to append after all results
8709 8803
          */
8710  
-        var generateSource = function(rule) {
8711  
-            if (!rule || !('name' in rule)) {
8712  
-                return "";
8713  
-            }
8714  
-            return 'net.csslint.' + rule.name.replace(/\s/g,'');
8715  
-        };
  8804
+        endFormat: function(){
  8805
+            return "</checkstyle>";
  8806
+        },
  8807
+        
  8808
+        /**
  8809
+         * Returns message when there is a file read error.
  8810
+         * @param {String} filename The name of the file that caused the error.
  8811
+         * @param {String} message The error message
  8812
+         * @return {String} The error message.
  8813
+         */
  8814
+        readError: function(filename, message) {
  8815
+            return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
  8816
+        },
8716 8817
 
8717 8818
         /**
8718  
-         * Replace special characters before write to output.
8719  
-         *
8720  
-         * Rules:
8721  
-         *  - single quotes is the escape sequence for double-quotes
8722  
-         *  - &lt; is the escape sequence for <
8723  
-         *  - &gt; is the escape sequence for >
8724  
-         *
8725  
-         * @param {String} message to escape
8726  
-         * @return escaped message as {String}
  8819
+         * Given CSS Lint results for a file, return output for this format.
  8820
+         * @param results {Object} with error and warning messages
  8821
+         * @param filename {String} relative file path
  8822
+         * @param options {Object} (UNUSED for now) specifies special handling of output
  8823
+         * @return {String} output for results
8727 8824
          */
8728  
-        var escapeSpecialCharacters = function(str) {
8729  
-            if (!str || str.constructor !== String) {
8730  
-                return "";
8731  
-            }
8732  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8733  
-        };
  8825
+        formatResults: function(results, filename, options) {
  8826
+            var messages = results.messages,
  8827
+                output = [];
8734 8828
 
8735  
-        if (messages.length > 0) {
8736  
-            output.push("<file name=\""+filename+"\">");
8737  
-            CSSLint.Util.forEach(messages, function (message, i) {
8738  
-                //ignore rollups for now
8739  
-                if (!message.rollup) {
8740  
-                  output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
8741  
-                      " message=\"" + escapeSpecialCharacters(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  8829
+            /**
  8830
+             * Generate a source string for a rule.
  8831
+             * Checkstyle source strings usually resemble Java class names e.g
  8832
+             * net.csslint.SomeRuleName
  8833
+             * @param {Object} rule
  8834
+             * @return rule source as {String}
  8835
+             */
  8836
+            var generateSource = function(rule) {
  8837
+                if (!rule || !('name' in rule)) {
  8838
+                    return "";
8742 8839
                 }
8743  
-            });
8744  
-            output.push("</file>");
  8840
+                return 'net.csslint.' + rule.name.replace(/\s/g,'');
  8841
+            };
  8842
+
  8843
+
  8844
+
  8845
+            if (messages.length > 0) {
  8846
+                output.push("<file name=\""+filename+"\">");
  8847
+                CSSLint.Util.forEach(messages, function (message, i) {
  8848
+                    //ignore rollups for now
  8849
+                    if (!message.rollup) {
  8850
+                      output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  8851
+                          " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  8852
+                    }
  8853
+                });
  8854
+                output.push("</file>");
  8855
+            }
  8856
+
  8857
+            return output.join("");
8745 8858
         }
  8859
+    });
8746 8860
 
8747  
-        return output.join("");
8748  
-    }
8749  
-});
  8861
+}());
8750 8862
 /*global CSSLint*/
8751 8863
 CSSLint.addFormatter({
8752 8864
     //format information
@@ -8844,6 +8956,7 @@ CSSLint.addFormatter({
8844 8956
          *
8845 8957
          * Rules:
8846 8958
          *  - single quotes is the escape sequence for double-quotes
  8959
+         *  - &amp; is the escape sequence for &
8847 8960
          *  - &lt; is the escape sequence for <
8848 8961
          *  - &gt; is the escape sequence for >
8849 8962
          * 
@@ -8854,7 +8967,7 @@ CSSLint.addFormatter({
8854 8967
             if (!str || str.constructor !== String) {
8855 8968
                 return "";
8856 8969
             }
8857  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  8970
+            return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8858 8971
         };
8859 8972
 
8860 8973
         if (messages.length > 0) {
@@ -8911,6 +9024,7 @@ CSSLint.addFormatter({
8911 9024
          *
8912 9025
          * Rules:
8913 9026
          *  - single quotes is the escape sequence for double-quotes
  9027
+         *  - &amp; is the escape sequence for &
8914 9028
          *  - &lt; is the escape sequence for <
8915 9029
          *  - &gt; is the escape sequence for >
8916 9030
          * 
@@ -8921,7 +9035,7 @@ CSSLint.addFormatter({
8921 9035
             if (!str || str.constructor !== String) {
8922 9036
                 return "";
8923 9037
             }
8924  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  9038
+            return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8925 9039
         };
8926 9040
 
8927 9041
         if (messages.length > 0) {
296  release/csslint-rhino.js
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 21
 THE SOFTWARE.
22 22
 
23 23
 */
24  
-/* Build time: 2-March-2012 02:47:11 */
  24
+/* Build time: 14-May-2012 10:24:48 */
25 25
 var CSSLint = (function(){
26 26
 
27 27
 /*!
@@ -47,7 +47,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47 47
 THE SOFTWARE.
48 48
 
49 49
 */
50  
-/* Version v0.1.6, Build time: 2-March-2012 02:44:32 */
  50
+/* Version v0.1.7, Build time: 4-May-2012 03:57:04 */
51 51
 var parserlib = {};
52 52
 (function(){
53 53
 
@@ -957,7 +957,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
957 957
 THE SOFTWARE.
958 958
 
959 959
 */
960  
-/* Version v0.1.6, Build time: 2-March-2012 02:44:32 */
  960
+/* Version v0.1.7, Build time: 4-May-2012 03:57:04 */
961 961
 (function(){
962 962
 var EventTarget = parserlib.util.EventTarget,
963 963
 TokenStreamBase = parserlib.util.TokenStreamBase,
@@ -2666,7 +2666,8 @@ Parser.prototype = function(){
2666 2666
                     expr        = null,
2667 2667
                     prio        = null,
2668 2668
                     error       = null,
2669  
-                    invalid     = null;
  2669
+                    invalid     = null,
  2670
+                    propertyName= "";
2670 2671
                 
2671 2672
                 property = this._property();
2672 2673
                 if (property !== null){
@@ -2683,8 +2684,20 @@ Parser.prototype = function(){
2683 2684
                     
2684 2685
                     prio = this._prio();
2685 2686
                     
  2687
+                    /*
  2688
+                     * If hacks should be allowed, then only check the root
  2689
+                     * property. If hacks should not be allowed, treat
  2690
+                     * _property or *property as invalid properties.
  2691
+                     */
  2692
+                    propertyName = property.toString();
  2693
+                    if (this.options.starHack && property.hack == "*" ||
  2694
+                            this.options.underscoreHack && property.hack == "_") {
  2695
+                         
  2696
+                        propertyName = property.text;
  2697
+                    }
  2698
+                    
2686 2699
                     try {
2687  
-                        this._validateProperty(property, expr);
  2700
+                        this._validateProperty(propertyName, expr);
2688 2701
                     } catch (ex) {
2689 2702
                         invalid = ex;
2690 2703
                     }
@@ -3525,6 +3538,7 @@ var Properties = {
3525 3538
     "background-repeat"             : { multi: "<repeat-style>" },
3526 3539
     "background-size"               : { multi: "<bg-size>", comma: true },
3527 3540
     "baseline-shift"                : "baseline | sub | super | <percentage> | <length>",
  3541
+    "behavior"                      : 1,
3528 3542
     "binding"                       : 1,
3529 3543
     "bleed"                         : "<length>",
3530 3544
     "bookmark-label"                : "<content> | <attr> | <string>",
@@ -3871,6 +3885,7 @@ var Properties = {
3871 3885
     "text-justify"                  : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
3872 3886
     "text-outline"                  : 1,
3873 3887
     "text-overflow"                 : 1,
  3888
+    "text-rendering"                : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
3874 3889
     "text-shadow"                   : 1,
3875 3890
     "text-transform"                : "capitalize | uppercase | lowercase | none | inherit",
3876 3891
     "text-wrap"                     : "normal | none | avoid",
@@ -5950,7 +5965,7 @@ var ValidationTypes = {
5950 5965
             i, len, found = false;
5951 5966
         
5952 5967
         for (i=0,len=args.length; i < len && !found; i++){
5953  
-            if (text == args[i]){
  5968
+            if (text == args[i].toLowerCase()){
5954 5969
                 found = true;
5955 5970
             }
5956 5971
         }
@@ -6042,7 +6057,7 @@ var ValidationTypes = {
6042 6057
         },        
6043 6058
         
6044 6059
         "<gradient>": function(part) {
6045  
-            return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial|linear)\-gradient/i.test(part);
  6060
+            return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
6046 6061
         },
6047 6062
         
6048 6063
         "<box>": function(part){
@@ -6134,6 +6149,18 @@ var ValidationTypes = {
6134 6149
                 part,
6135 6150
                 i, len;
6136 6151
             
  6152
+/*
  6153
+<position> = [
  6154
+  [ left | center | right | top | bottom | <percentage> | <length> ]
  6155
+|
  6156
+  [ left | center | right | <percentage> | <length> ]
  6157
+  [ top | center | bottom | <percentage> | <length> ]
  6158
+|
  6159
+  [ center | [ left | right ] [ <percentage> | <length> ]? ] &&
  6160
+  [ center | [ top | bottom ] [ <percentage> | <length> ]? ]
  6161
+]
  6162
+
  6163
+*/            
6137 6164
                 
6138 6165
             if (ValidationTypes.isAny(expression, "top | bottom")) {
6139 6166
                 result = true;
@@ -6306,7 +6333,7 @@ var CSSLint = (function(){
6306 6333
         formatters = [],
6307 6334
         api        = new parserlib.util.EventTarget();
6308 6335
         
6309  
-    api.version = "0.9.7";
  6336
+    api.version = "0.9.8";
6310 6337
 
6311 6338
     //-------------------------------------------------------------------------
6312 6339
     // Rule Management
@@ -7633,7 +7660,7 @@ CSSLint.addRule({
7633 7660
         parser.addListener("endstylesheet", function(){
7634 7661
             reporter.stat("important", count);
7635 7662
             if (count >= 10){
7636  
-                reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specifity issues.", rule);
  7663
+                reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
7637 7664
             }
7638 7665
         });
7639 7666
     }
@@ -8290,8 +8317,35 @@ CSSLint.addRule({
8290 8317
 
8291 8318
 });
8292 8319
 /*
8293  
- * Rule: Don't use text-indent for image replacement if you need to support rtl. 
8294  
- * 
  8320
+ * Rule: Don't use properties with a star prefix.
  8321
+ *
  8322
+ */
  8323
+/*global CSSLint*/
  8324
+CSSLint.addRule({
  8325
+
  8326
+    //rule information
  8327
+    id: "star-property-hack",
  8328
+    name: "Disallow properties with a star prefix",
  8329
+    desc: "Checks for the star property hack (targets IE6/7)",
  8330
+    browsers: "All",
  8331
+
  8332
+    //initialization
  8333
+    init: function(parser, reporter){
  8334
+        var rule = this;
  8335
+
  8336
+        //check if property name starts with "*"
  8337
+        parser.addListener("property", function(event){
  8338
+            var property = event.property;
  8339
+
  8340
+            if (property.hack == "*") {
  8341
+                reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
  8342
+            }
  8343
+        });
  8344
+    }
  8345
+});
  8346
+/*
  8347
+ * Rule: Don't use text-indent for image replacement if you need to support rtl.
  8348
+ *
8295 8349
  */
8296 8350
 /*global CSSLint*/
8297 8351
 CSSLint.addRule({
@@ -8301,27 +8355,29 @@ CSSLint.addRule({
8301 8355
     name: "Disallow negative text-indent",
8302 8356
     desc: "Checks for text indent less than -99px",
8303 8357
     browsers: "All",
8304  
-    
  8358
+
8305 8359
     //initialization
8306 8360
     init: function(parser, reporter){
8307 8361
         var rule = this,
8308  
-            textIndent = false;
8309  
-            
8310  
-            
  8362
+            textIndent,
  8363
+            direction;
  8364
+
  8365
+
8311 8366
         function startRule(event){
8312 8367
             textIndent = false;
  8368
+            direction = "inherit";
8313 8369
         }
8314  
-        
  8370
+
8315 8371
         //event handler for end of rules
8316 8372
         function endRule(event){
8317  
-            if (textIndent){
  8373
+            if (textIndent && direction != "ltr"){
8318 8374
                 reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule);
8319 8375
             }
8320  
-        }        
8321  
-        
  8376
+        }
  8377
+
8322 8378
         parser.addListener("startrule", startRule);
8323 8379
         parser.addListener("startfontface", startRule);
8324  
-    
  8380
+
8325 8381
         //check for use of "font-size"
8326 8382
         parser.addListener("property", function(event){
8327 8383
             var name = event.property.toString().toLowerCase(),
@@ -8330,17 +8386,44 @@ CSSLint.addRule({
8330 8386
             if (name == "text-indent" && value.parts[0].value < -99){
8331 8387
                 textIndent = event.property;
8332 8388
             } else if (name == "direction" && value == "ltr"){
8333  
-                textIndent = false;
  8389
+                direction = "ltr";
8334 8390
             }
8335 8391
         });
8336 8392
 
8337 8393
         parser.addListener("endrule", endRule);
8338  
-        parser.addListener("endfontface", endRule);     
  8394
+        parser.addListener("endfontface", endRule);
8339 8395
 
8340 8396
     }
8341 8397
 
8342 8398
 });
8343 8399
 /*
  8400
+ * Rule: Don't use properties with a underscore prefix.
  8401
+ *
  8402
+ */
  8403
+/*global CSSLint*/
  8404
+CSSLint.addRule({
  8405
+
  8406
+    //rule information
  8407
+    id: "underscore-property-hack",
  8408
+    name: "Disallow properties with an underscore prefix",
  8409
+    desc: "Checks for the underscore property hack (targets IE6)",
  8410
+    browsers: "All",
  8411
+
  8412
+    //initialization
  8413
+    init: function(parser, reporter){
  8414
+        var rule = this;
  8415
+
  8416
+        //check if property name starts with "_"
  8417
+        parser.addListener("property", function(event){
  8418
+            var property = event.property;
  8419
+
  8420
+            if (property.hack == "_") {
  8421
+                reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
  8422
+            }
  8423
+        });
  8424
+    }
  8425
+});
  8426
+/*
8344 8427
  * Rule: Headings (h1-h6) should be defined only once.
8345 8428
  */
8346 8429
 /*global CSSLint*/
@@ -8669,85 +8752,114 @@ CSSLint.addRule({
8669 8752
 
8670 8753
 });
8671 8754
 /*global CSSLint*/
8672  
-CSSLint.addFormatter({
8673  
-    //format information
8674  
-    id: "checkstyle-xml",
8675  
-    name: "Checkstyle XML format",
  8755
+(function() {
8676 8756
 
8677 8757
     /**
8678  
-     * Return opening root XML tag.
8679  
-     * @return {String} to prepend before all results
  8758
+     * Replace special characters before write to output.
  8759
+     *
  8760
+     * Rules:
  8761
+     *  - single quotes is the escape sequence for double-quotes
  8762
+     *  - &amp; is the escape sequence for &
  8763
+     *  - &lt; is the escape sequence for <
  8764
+     *  - &gt; is the escape sequence for >
  8765
+     *
  8766
+     * @param {String} message to escape
  8767
+     * @return escaped message as {String}
8680 8768
      */
8681  
-    startFormat: function(){
8682  
-        return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
8683  
-    },
  8769
+    var xmlEscape = function(str) {
  8770
+        if (!str || str.constructor !== String) {
  8771
+            return "";
  8772
+        }
  8773
+        
  8774
+        return str.replace(/[\"&><]/g, function(match) {
  8775
+            switch (match) {
  8776
+                case "\"":
  8777
+                    return "&quot;";
  8778
+                case "&":
  8779
+                    return "&amp;";
  8780
+                case "<":
  8781
+                    return "&lt;";
  8782
+                case ">":
  8783
+                    return "&gt;";            
  8784
+            }
  8785
+        });
  8786
+    };
8684 8787
 
8685  
-    /**
8686  
-     * Return closing root XML tag.
8687  
-     * @return {String} to append after all results
8688  
-     */
8689  
-    endFormat: function(){
8690  
-        return "</checkstyle>";
8691  
-    },
  8788
+    CSSLint.addFormatter({
  8789
+        //format information
  8790
+        id: "checkstyle-xml",
  8791
+        name: "Checkstyle XML format",
8692 8792
 
8693  
-    /**
8694  
-     * Given CSS Lint results for a file, return output for this format.
8695  
-     * @param results {Object} with error and warning messages
8696  
-     * @param filename {String} relative file path
8697  
-     * @param options {Object} (UNUSED for now) specifies special handling of output
8698  
-     * @return {String} output for results
8699  
-     */
8700  
-    formatResults: function(results, filename, options) {
8701  
-        var messages = results.messages,
8702  
-            output = [];
  8793
+        /**
  8794
+         * Return opening root XML tag.
  8795
+         * @return {String} to prepend before all results
  8796
+         */
  8797
+        startFormat: function(){
  8798
+            return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
  8799
+        },
8703 8800
 
8704 8801
         /**
8705  
-         * Generate a source string for a rule.
8706  
-         * Checkstyle source strings usually resemble Java class names e.g
8707  
-         * net.csslint.SomeRuleName
8708  
-         * @param {Object} rule
8709  
-         * @return rule source as {String}
  8802
+         * Return closing root XML tag.
  8803
+         * @return {String} to append after all results
8710 8804
          */
8711  
-        var generateSource = function(rule) {
8712  
-            if (!rule || !('name' in rule)) {
8713  
-                return "";
8714  
-            }
8715  
-            return 'net.csslint.' + rule.name.replace(/\s/g,'');
8716  
-        };
  8805
+        endFormat: function(){
  8806
+            return "</checkstyle>";
  8807
+        },
  8808
+        
  8809
+        /**
  8810
+         * Returns message when there is a file read error.
  8811
+         * @param {String} filename The name of the file that caused the error.
  8812
+         * @param {String} message The error message
  8813
+         * @return {String} The error message.
  8814
+         */
  8815
+        readError: function(filename, message) {
  8816
+            return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
  8817
+        },
8717 8818
 
8718 8819
         /**
8719  
-         * Replace special characters before write to output.
8720  
-         *
8721  
-         * Rules:
8722  
-         *  - single quotes is the escape sequence for double-quotes
8723  
-         *  - &lt; is the escape sequence for <
8724  
-         *  - &gt; is the escape sequence for >
8725  
-         *
8726  
-         * @param {String} message to escape
8727  
-         * @return escaped message as {String}
  8820
+         * Given CSS Lint results for a file, return output for this format.
  8821
+         * @param results {Object} with error and warning messages
  8822
+         * @param filename {String} relative file path
  8823
+         * @param options {Object} (UNUSED for now) specifies special handling of output
  8824
+         * @return {String} output for results
8728 8825
          */
8729  
-        var escapeSpecialCharacters = function(str) {
8730  
-            if (!str || str.constructor !== String) {
8731  
-                return "";
8732  
-            }
8733  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8734  
-        };
  8826
+        formatResults: function(results, filename, options) {
  8827
+            var messages = results.messages,
  8828
+                output = [];
8735 8829
 
8736  
-        if (messages.length > 0) {
8737  
-            output.push("<file name=\""+filename+"\">");
8738  
-            CSSLint.Util.forEach(messages, function (message, i) {
8739  
-                //ignore rollups for now
8740  
-                if (!message.rollup) {
8741  
-                  output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
8742  
-                      " message=\"" + escapeSpecialCharacters(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  8830
+            /**
  8831
+             * Generate a source string for a rule.
  8832
+             * Checkstyle source strings usually resemble Java class names e.g
  8833
+             * net.csslint.SomeRuleName
  8834
+             * @param {Object} rule
  8835
+             * @return rule source as {String}
  8836
+             */
  8837
+            var generateSource = function(rule) {
  8838
+                if (!rule || !('name' in rule)) {
  8839
+                    return "";
8743 8840
                 }
8744  
-            });
8745  
-            output.push("</file>");
  8841
+                return 'net.csslint.' + rule.name.replace(/\s/g,'');
  8842
+            };
  8843
+
  8844
+
  8845
+
  8846
+            if (messages.length > 0) {
  8847
+                output.push("<file name=\""+filename+"\">");
  8848
+                CSSLint.Util.forEach(messages, function (message, i) {
  8849
+                    //ignore rollups for now
  8850
+                    if (!message.rollup) {
  8851
+                      output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  8852
+                          " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  8853
+                    }
  8854
+                });
  8855
+                output.push("</file>");
  8856
+            }
  8857
+
  8858
+            return output.join("");
8746 8859
         }
  8860
+    });
8747 8861
 
8748  
-        return output.join("");
8749  
-    }
8750  
-});
  8862
+}());
8751 8863
 /*global CSSLint*/
8752 8864
 CSSLint.addFormatter({
8753 8865
     //format information
@@ -8845,6 +8957,7 @@ CSSLint.addFormatter({
8845 8957
          *
8846 8958
          * Rules:
8847 8959
          *  - single quotes is the escape sequence for double-quotes
  8960
+         *  - &amp; is the escape sequence for &
8848 8961
          *  - &lt; is the escape sequence for <
8849 8962
          *  - &gt; is the escape sequence for >
8850 8963
          * 
@@ -8855,7 +8968,7 @@ CSSLint.addFormatter({
8855 8968
             if (!str || str.constructor !== String) {
8856 8969
                 return "";
8857 8970
             }
8858  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  8971
+            return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8859 8972
         };
8860 8973
 
8861 8974
         if (messages.length > 0) {
@@ -8912,6 +9025,7 @@ CSSLint.addFormatter({
8912 9025
          *
8913 9026
          * Rules:
8914 9027
          *  - single quotes is the escape sequence for double-quotes
  9028
+         *  - &amp; is the escape sequence for &
8915 9029
          *  - &lt; is the escape sequence for <
8916 9030
          *  - &gt; is the escape sequence for >
8917 9031
          * 
@@ -8922,7 +9036,7 @@ CSSLint.addFormatter({
8922 9036
             if (!str || str.constructor !== String) {
8923 9037
                 return "";
8924 9038
             }
8925  
-            return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  9039
+            return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8926 9040
         };
8927 9041
 
8928 9042
         if (messages.length > 0) {
@@ -9089,7 +9203,11 @@ function cli(api){
9089 9203
             exitCode = 0;
9090 9204
 
9091 9205
         if (!input) {
9092  
-            api.print("csslint: Could not read file data in " + relativeFilePath + ". Is the file empty?");
  9206
+            if (formatter.readError) {
  9207
+                api.print(formatter.readError(relativeFilePath, "Could not read file data. Is the file empty?"));
  9208
+            } else {
  9209
+                api.print("csslint: Could not read file data in " + relativeFilePath + ". Is the file empty?");
  9210
+            }
9093 9211
             exitCode = 1;
9094 9212
         } else {
9095 9213
             //var relativeFilePath = getRelativePath(api.getWorkingDirectory(), fullFilePath);
101  release/csslint-tests.js
@@ -87,14 +87,14 @@
87 87
         },
88 88
 
89 89
         "Formatter should escape special characters": function() {
90  
-            var specialCharsSting = 'sneaky, "sneaky", <sneaky>',
  90
+            var specialCharsSting = 'sneaky, "sneaky", <sneaky>, sneak & sneaky',
91 91
                 result = { messages: [
92 92
                      { type: "warning", line: 1, col: 1, message: specialCharsSting, evidence: "ALSO BOGUS", rule: [] },
93 93
                      { type: "error", line: 2, col: 1, message: specialCharsSting, evidence: "ALSO BOGUS", rule: [] }
94 94
                 ], stats: [] },
95 95
                 file = "<file name=\"FILE\">",
96  
-                error1 = "<error line=\"1\" column=\"1\" severity=\"warning\" message=\"sneaky, 'sneaky', &lt;sneaky&gt;\" source=\"\"/>",
97  
-                error2 = "<error line=\"2\" column=\"1\" severity=\"error\" message=\"sneaky, 'sneaky', &lt;sneaky&gt;\" source=\"\"/>",
  96
+                error1 = "<error line=\"1\" column=\"1\" severity=\"warning\" message=\"sneaky, &quot;sneaky&quot;, &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
  97
+                error2 = "<error line=\"2\" column=\"1\" severity=\"error\" message=\"sneaky, &quot;sneaky&quot;, &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
98 98
                 expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>" + file + error1 + error2 + "</file></checkstyle>",
99 99
                 actual = CSSLint.format(result, "FILE", "checkstyle-xml");
100 100
             Assert.areEqual(expected, actual);
@@ -179,14 +179,14 @@
179 179
         },
180 180
 
181 181
         "Formatter should escape double quotes": function() {
182  
-            var doubleQuotedEvidence = 'sneaky, "sneaky"',
  182
+            var doubleQuotedEvidence = 'sneaky, "sneaky", <sneaky>, sneak & sneaky',
183 183
                 result = { messages: [
184 184
                      { type: "warning", line: 1, col: 1, message: "BOGUS", evidence: doubleQuotedEvidence, rule: [] },
185 185
                      { type: "error", line: 2, col: 1, message: "BOGUS", evidence: doubleQuotedEvidence, rule: [] }
186 186
                 ], stats: [] },
187 187
                 file = "<file name=\"FILE\">",
188  
-                error1 = "<issue line=\"1\" char=\"1\" severity=\"warning\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky'\"/>",
189  
-                error2 = "<issue line=\"2\" char=\"1\" severity=\"error\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky'\"/>",
  188
+                error1 = "<issue line=\"1\" char=\"1\" severity=\"warning\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\"/>",
  189
+                error2 = "<issue line=\"2\" char=\"1\" severity=\"error\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\"/>",
190 190
                 expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>" + file + error1 + error2 + "</file></csslint>",
191 191
                 actual = CSSLint.format(result, "FILE", "csslint-xml");
192 192
             Assert.areEqual(expected, actual);
@@ -223,14 +223,14 @@
223 223
         },
224 224
 
225 225
         "Formatter should escape double quotes": function() {
226  
-            var doubleQuotedEvidence = 'sneaky, "sneaky"',
  226
+            var doubleQuotedEvidence = 'sneaky, "sneaky", <sneaky>, sneak & sneaky',
227 227
                 result = { messages: [
228 228
                      { type: "warning", line: 1, col: 1, message: "BOGUS", evidence: doubleQuotedEvidence, rule: [] },
229 229
                      { type: "error", line: 2, col: 1, message: "BOGUS", evidence: doubleQuotedEvidence, rule: [] }
230 230
                 ], stats: [] },
231 231
                 file = "<file name=\"FILE\">",
232  
-                error1 = "<issue line=\"1\" char=\"1\" severity=\"warning\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky'\"/>",
233  
-                error2 = "<issue line=\"2\" char=\"1\" severity=\"error\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky'\"/>",
  232
+                error1 = "<issue line=\"1\" char=\"1\" severity=\"warning\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\"/>",
  233
+                error2 = "<issue line=\"2\" char=\"1\" severity=\"error\" reason=\"BOGUS\" evidence=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\"/>",
234 234
                 expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>" + file + error1 + error2 + "</file></lint>",
235 235
                 actual = CSSLint.format(result, "FILE", "lint-xml");
236 236
             Assert.areEqual(expected, actual);
@@ -1318,7 +1318,7 @@ background: -ms-linear-gradient(top, #1e5799 ,#2989d8 ,#207cca ,#7db9e8 );
1318 1318
             var result = CSSLint.verify(css, { "important": 1 });
1319 1319
             Assert.areEqual(11, result.messages.length);
1320 1320
             Assert.areEqual("warning", result.messages[10].type);
1321  
-            Assert.areEqual("Too many !important declarations (10), try to use less than 10 to avoid specifity issues.", result.messages[10].message);
  1321
+            Assert.areEqual("Too many !important declarations (10), try to use less than 10 to avoid specificity issues.", result.messages[10].message);
1322 1322
         }
1323 1323
 
1324 1324
     }));
@@ -1346,6 +1346,16 @@ background: -ms-linear-gradient(top, #1e5799 ,#2989d8 ,#207cca ,#7db9e8 );
1346 1346
             Assert.areEqual(0, result.messages.length);
1347 1347
         },
1348 1348
 
  1349
+        "Using a known property with the star hack should not result in a warning": function(){
  1350
+            var result = CSSLint.verify("h1 { *color: red;}", { "known-properties": 1 });
  1351
+            Assert.areEqual(0, result.messages.length);
  1352
+        },
  1353
+
  1354
+        "Using a known property with the underscore hack should not result in a warning": function(){
  1355
+            var result = CSSLint.verify("h1 { _color: red;}", { "known-properties": 1 });
  1356
+            Assert.areEqual(0, result.messages.length);
  1357
+        },
  1358
+
1349 1359
         "Using a vendor-prefix property should not result in a warning": function(){
1350 1360
             var result = CSSLint.verify("h2 { -moz-border-radius: 5px; }", { "known-properties": 1 });
1351 1361
             Assert.areEqual(0, result.messages.length);        
@@ -1569,7 +1579,32 @@ background: -ms-linear-gradient(top, #1e5799 ,#2989d8 ,#207cca ,#7db9e8 );
1569 1579
     var Assert = YUITest.Assert;
1570 1580
 
1571 1581
     YUITest.TestRunner.add(new YUITest.TestCase({
1572  
-    
  1582
+
  1583
+        name: "star-property-hack Rule Errors",
  1584
+
  1585
+        "a property with a star prefix should result in a warning": function(){
  1586
+            var result = CSSLint.verify(".foo{*width: 100px;}", {"star-property-hack": 1 });
  1587
+            Assert.areEqual(1, result.messages.length);
  1588
+            Assert.areEqual("warning", result.messages[0].type);
  1589
+            Assert.areEqual("Property with star prefix found.", result.messages[0].message);
  1590
+        },