css_validator 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,30 +1,4 @@
1
1
  /*!
2
- CSSLint
3
- Copyright (c) 2013 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
22
-
23
- */
24
- /* Build: v0.10.0 15-August-2013 01:07:22 */
25
- var exports = exports || {};
26
- var CSSLint = (function(){
27
- /*!
28
2
  Parser-Lib
29
3
  Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.
30
4
 
@@ -47,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
21
  THE SOFTWARE.
48
22
 
49
23
  */
50
- /* Version v0.2.3, Build time: 19-June-2013 11:16:15 */
24
+ /* Version v0.2.4, Build time: 7-January-2014 07:32:49 */
51
25
  var parserlib = {};
52
26
  (function(){
53
27
 
@@ -957,7 +931,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
957
931
  THE SOFTWARE.
958
932
 
959
933
  */
960
- /* Version v0.2.3, Build time: 19-June-2013 11:16:15 */
934
+ /* Version v0.2.4, Build time: 7-January-2014 07:32:49 */
961
935
  (function(){
962
936
  var EventTarget = parserlib.util.EventTarget,
963
937
  TokenStreamBase = parserlib.util.TokenStreamBase,
@@ -992,6 +966,7 @@ var Colors = {
992
966
  darkcyan :"#008b8b",
993
967
  darkgoldenrod :"#b8860b",
994
968
  darkgray :"#a9a9a9",
969
+ darkgrey :"#a9a9a9",
995
970
  darkgreen :"#006400",
996
971
  darkkhaki :"#bdb76b",
997
972
  darkmagenta :"#8b008b",
@@ -1003,11 +978,13 @@ var Colors = {
1003
978
  darkseagreen :"#8fbc8f",
1004
979
  darkslateblue :"#483d8b",
1005
980
  darkslategray :"#2f4f4f",
981
+ darkslategrey :"#2f4f4f",
1006
982
  darkturquoise :"#00ced1",
1007
983
  darkviolet :"#9400d3",
1008
984
  deeppink :"#ff1493",
1009
985
  deepskyblue :"#00bfff",
1010
986
  dimgray :"#696969",
987
+ dimgrey :"#696969",
1011
988
  dodgerblue :"#1e90ff",
1012
989
  firebrick :"#b22222",
1013
990
  floralwhite :"#fffaf0",
@@ -1018,6 +995,7 @@ var Colors = {
1018
995
  gold :"#ffd700",
1019
996
  goldenrod :"#daa520",
1020
997
  gray :"#808080",
998
+ grey :"#808080",
1021
999
  green :"#008000",
1022
1000
  greenyellow :"#adff2f",
1023
1001
  honeydew :"#f0fff0",
@@ -1035,12 +1013,14 @@ var Colors = {
1035
1013
  lightcyan :"#e0ffff",
1036
1014
  lightgoldenrodyellow :"#fafad2",
1037
1015
  lightgray :"#d3d3d3",
1016
+ lightgrey :"#d3d3d3",
1038
1017
  lightgreen :"#90ee90",
1039
1018
  lightpink :"#ffb6c1",
1040
1019
  lightsalmon :"#ffa07a",
1041
1020
  lightseagreen :"#20b2aa",
1042
1021
  lightskyblue :"#87cefa",
1043
1022
  lightslategray :"#778899",
1023
+ lightslategrey :"#778899",
1044
1024
  lightsteelblue :"#b0c4de",
1045
1025
  lightyellow :"#ffffe0",
1046
1026
  lime :"#00ff00",
@@ -1093,6 +1073,7 @@ var Colors = {
1093
1073
  skyblue :"#87ceeb",
1094
1074
  slateblue :"#6a5acd",
1095
1075
  slategray :"#708090",
1076
+ slategrey :"#708090",
1096
1077
  snow :"#fffafa",
1097
1078
  springgreen :"#00ff7f",
1098
1079
  steelblue :"#4682b4",
@@ -1118,6 +1099,7 @@ var Colors = {
1118
1099
  buttontext :"Text on push buttons.",
1119
1100
  captiontext :"Text in caption, size box, and scrollbar arrow box.",
1120
1101
  graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
1102
+ greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",
1121
1103
  highlight :"Item(s) selected in a control.",
1122
1104
  highlighttext :"Text of item(s) selected in a control.",
1123
1105
  inactiveborder :"Inactive window border.",
@@ -2812,7 +2794,7 @@ Parser.prototype = function(){
2812
2794
 
2813
2795
  var tokenStream = this._tokenStream,
2814
2796
  values = [],
2815
- //valueParts = [],
2797
+ //valueParts = [],
2816
2798
  value = null,
2817
2799
  operator = null;
2818
2800
 
@@ -2829,9 +2811,9 @@ Parser.prototype = function(){
2829
2811
  values.push(operator);
2830
2812
  } /*else {
2831
2813
  //if there's not an operator, you have a full value
2832
- values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
2833
- valueParts = [];
2834
- }*/
2814
+ values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
2815
+ valueParts = [];
2816
+ }*/
2835
2817
 
2836
2818
  value = this._term();
2837
2819
 
@@ -2843,7 +2825,7 @@ Parser.prototype = function(){
2843
2825
  } while(true);
2844
2826
  }
2845
2827
 
2846
- //cleanup
2828
+ //cleanup
2847
2829
  /*if (valueParts.length){
2848
2830
  values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
2849
2831
  }*/
@@ -3534,6 +3516,12 @@ nth
3534
3516
  var Properties = {
3535
3517
 
3536
3518
  //A
3519
+ "align-items" : "flex-start | flex-end | center | baseline | stretch",
3520
+ "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
3521
+ "align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
3522
+ "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch",
3523
+ "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
3524
+ "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
3537
3525
  "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
3538
3526
  "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
3539
3527
  "animation" : 1,
@@ -3729,15 +3717,24 @@ var Properties = {
3729
3717
  "border-top-width" : "<border-width>",
3730
3718
  "border-width" : { multi: "<border-width>", max: 4 },
3731
3719
  "bottom" : "<margin-width> | inherit",
3732
- "box-align" : "start | end | center | baseline | stretch", //http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/
3733
- "box-decoration-break" : "slice |clone",
3734
- "box-direction" : "normal | reverse | inherit",
3735
- "box-flex" : "<number>",
3736
- "box-flex-group" : "<integer>",
3737
- "box-lines" : "single | multiple",
3738
- "box-ordinal-group" : "<integer>",
3739
- "box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
3740
- "box-pack" : "start | end | center | justify",
3720
+ "-moz-box-align" : "start | end | center | baseline | stretch",
3721
+ "-moz-box-decoration-break" : "slice |clone",
3722
+ "-moz-box-direction" : "normal | reverse | inherit",
3723
+ "-moz-box-flex" : "<number>",
3724
+ "-moz-box-flex-group" : "<integer>",
3725
+ "-moz-box-lines" : "single | multiple",
3726
+ "-moz-box-ordinal-group" : "<integer>",
3727
+ "-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
3728
+ "-moz-box-pack" : "start | end | center | justify",
3729
+ "-webkit-box-align" : "start | end | center | baseline | stretch",
3730
+ "-webkit-box-decoration-break" : "slice |clone",
3731
+ "-webkit-box-direction" : "normal | reverse | inherit",
3732
+ "-webkit-box-flex" : "<number>",
3733
+ "-webkit-box-flex-group" : "<integer>",
3734
+ "-webkit-box-lines" : "single | multiple",
3735
+ "-webkit-box-ordinal-group" : "<integer>",
3736
+ "-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
3737
+ "-webkit-box-pack" : "start | end | center | justify",
3741
3738
  "box-shadow" : function (expression) {
3742
3739
  var result = false,
3743
3740
  part;
@@ -3783,7 +3780,7 @@ var Properties = {
3783
3780
 
3784
3781
  //D
3785
3782
  "direction" : "ltr | rtl | inherit",
3786
- "display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | box | inline-box | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box",
3783
+ "display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex",
3787
3784
  "dominant-baseline" : 1,
3788
3785
  "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
3789
3786
  "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
@@ -3800,6 +3797,26 @@ var Properties = {
3800
3797
  "filter" : 1,
3801
3798
  "fit" : "fill | hidden | meet | slice",
3802
3799
  "fit-position" : 1,
3800
+ "flex" : "none | [ <flex-grow> <flex-shrink>? || <flex-basis>",
3801
+ "flex-basis" : "<width>",
3802
+ "flex-direction" : "row | row-reverse | column | column-reverse",
3803
+ "flex-flow" : "<flex-direction> || <flex-wrap>",
3804
+ "flex-grow" : "<number>",
3805
+ "flex-shrink" : "<number>",
3806
+ "flex-wrap" : "nowrap | wrap | wrap-reverse",
3807
+ "-webkit-flex" : "none | [ <flex-grow> <flex-shrink>? || <flex-basis>",
3808
+ "-webkit-flex-basis" : "<width>",
3809
+ "-webkit-flex-direction" : "row | row-reverse | column | column-reverse",
3810
+ "-webkit-flex-flow" : "<flex-direction> || <flex-wrap>",
3811
+ "-webkit-flex-grow" : "<number>",
3812
+ "-webkit-flex-shrink" : "<number>",
3813
+ "-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse",
3814
+ "-ms-flex" : "[[ <number> <number>? ] || [ <length> || <percentage> || auto ] ] | none",
3815
+ "-ms-flex-align" : "start | end | center | stretch | baseline",
3816
+ "-ms-flex-direction" : "row | column | row-reverse | column-reverse | inherit",
3817
+ "-ms-flex-order" : "<number>",
3818
+ "-ms-flex-pack" : "start | end | center | justify",
3819
+ "-ms-flex-wrap" : "nowrap | wrap | wrap-reverse",
3803
3820
  "float" : "left | right | none | inherit",
3804
3821
  "float-offset" : 1,
3805
3822
  "font" : 1,
@@ -3843,6 +3860,10 @@ var Properties = {
3843
3860
  "image-resolution" : 1,
3844
3861
  "inline-box-align" : "initial | last | <integer>",
3845
3862
 
3863
+ //J
3864
+ "justify-content" : "flex-start | flex-end | center | space-between | space-around",
3865
+ "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around",
3866
+
3846
3867
  //L
3847
3868
  "left" : "<margin-width> | inherit",
3848
3869
  "letter-spacing" : "<length> | normal | inherit",
@@ -3886,6 +3907,8 @@ var Properties = {
3886
3907
 
3887
3908
  //O
3888
3909
  "opacity" : "<number> | inherit",
3910
+ "order" : "<integer>",
3911
+ "-webkit-order" : "<integer>",
3889
3912
  "orphans" : "<integer> | inherit",
3890
3913
  "outline" : 1,
3891
3914
  "outline-color" : "<color> | invert | inherit",
@@ -3894,6 +3917,7 @@ var Properties = {
3894
3917
  "outline-width" : "<border-width> | inherit",
3895
3918
  "overflow" : "visible | hidden | scroll | auto | inherit",
3896
3919
  "overflow-style" : 1,
3920
+ "overflow-wrap" : "normal | break-word",
3897
3921
  "overflow-x" : 1,
3898
3922
  "overflow-y" : 1,
3899
3923
 
@@ -3971,6 +3995,8 @@ var Properties = {
3971
3995
  "text-transform" : "capitalize | uppercase | lowercase | none | inherit",
3972
3996
  "text-wrap" : "normal | none | avoid",
3973
3997
  "top" : "<margin-width> | inherit",
3998
+ "-ms-touch-action" : "auto | none | pan-x | pan-y",
3999
+ "touch-action" : "auto | none | pan-x | pan-y",
3974
4000
  "transform" : 1,
3975
4001
  "transform-origin" : 1,
3976
4002
  "transform-style" : 1,
@@ -3981,7 +4007,7 @@ var Properties = {
3981
4007
  "transition-timing-function" : 1,
3982
4008
 
3983
4009
  //U
3984
- "unicode-bidi" : "normal | embed | bidi-override | inherit",
4010
+ "unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit",
3985
4011
  "user-modify" : "read-only | read-write | write-only | inherit",
3986
4012
  "user-select" : "none | text | toggle | element | elements | all | inherit",
3987
4013
 
@@ -4005,7 +4031,8 @@ var Properties = {
4005
4031
  "width" : "<length> | <percentage> | auto | inherit" ,
4006
4032
  "word-break" : "normal | keep-all | break-all",
4007
4033
  "word-spacing" : "<length> | normal | inherit",
4008
- "word-wrap" : 1,
4034
+ "word-wrap" : "normal | break-word",
4035
+ "writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit",
4009
4036
 
4010
4037
  //Z
4011
4038
  "z-index" : "<integer> | auto | inherit",
@@ -4276,9 +4303,6 @@ function PropertyValuePart(text, line, col){
4276
4303
 
4277
4304
  }
4278
4305
 
4279
- } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
4280
- this.type = "percentage";
4281
- this.value = +RegExp.$1;
4282
4306
  } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
4283
4307
  this.type = "percentage";
4284
4308
  this.value = +RegExp.$1;
@@ -4375,6 +4399,7 @@ PropertyValuePart.prototype.constructor = PropertyValuePart;
4375
4399
  PropertyValuePart.fromToken = function(token){
4376
4400
  return new PropertyValuePart(token.value, token.startLine, token.startCol);
4377
4401
  };
4402
+
4378
4403
  var Pseudos = {
4379
4404
  ":first-letter": 1,
4380
4405
  ":first-line": 1,
@@ -4668,12 +4693,12 @@ function isIdentStart(c){
4668
4693
  }
4669
4694
 
4670
4695
  function mix(receiver, supplier){
4671
- for (var prop in supplier){
4672
- if (supplier.hasOwnProperty(prop)){
4673
- receiver[prop] = supplier[prop];
4674
- }
4675
- }
4676
- return receiver;
4696
+ for (var prop in supplier){
4697
+ if (supplier.hasOwnProperty(prop)){
4698
+ receiver[prop] = supplier[prop];
4699
+ }
4700
+ }
4701
+ return receiver;
4677
4702
  }
4678
4703
 
4679
4704
  //-----------------------------------------------------------------------------
@@ -4689,7 +4714,7 @@ function mix(receiver, supplier){
4689
4714
  * @namespace parserlib.css
4690
4715
  */
4691
4716
  function TokenStream(input){
4692
- TokenStreamBase.call(this, input, Tokens);
4717
+ TokenStreamBase.call(this, input, Tokens);
4693
4718
  }
4694
4719
 
4695
4720
  TokenStream.prototype = mix(new TokenStreamBase(), {
@@ -5662,7 +5687,7 @@ var Tokens = [
5662
5687
  { name: "FONT_FACE_SYM", text: "@font-face"},
5663
5688
  { name: "CHARSET_SYM", text: "@charset"},
5664
5689
  { name: "NAMESPACE_SYM", text: "@namespace"},
5665
- { name: "VIEWPORT_SYM", text: "@viewport"},
5690
+ { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]},
5666
5691
  { name: "UNKNOWN_SYM" },
5667
5692
  //{ name: "ATKEYWORD"},
5668
5693
 
@@ -6429,3223 +6454,3 @@ exports[prop] = parserlib[prop];
6429
6454
  }
6430
6455
  })();
6431
6456
 
6432
-
6433
- /**
6434
- * Main CSSLint object.
6435
- * @class CSSLint
6436
- * @static
6437
- * @extends parserlib.util.EventTarget
6438
- */
6439
- /*global parserlib, Reporter*/
6440
- var CSSLint = (function(){
6441
-
6442
- var rules = [],
6443
- formatters = [],
6444
- embeddedRuleset = /\/\*csslint([^\*]*)\*\//,
6445
- api = new parserlib.util.EventTarget();
6446
-
6447
- api.version = "0.10.0";
6448
-
6449
- //-------------------------------------------------------------------------
6450
- // Rule Management
6451
- //-------------------------------------------------------------------------
6452
-
6453
- /**
6454
- * Adds a new rule to the engine.
6455
- * @param {Object} rule The rule to add.
6456
- * @method addRule
6457
- */
6458
- api.addRule = function(rule){
6459
- rules.push(rule);
6460
- rules[rule.id] = rule;
6461
- };
6462
-
6463
- /**
6464
- * Clears all rule from the engine.
6465
- * @method clearRules
6466
- */
6467
- api.clearRules = function(){
6468
- rules = [];
6469
- };
6470
-
6471
- /**
6472
- * Returns the rule objects.
6473
- * @return An array of rule objects.
6474
- * @method getRules
6475
- */
6476
- api.getRules = function(){
6477
- return [].concat(rules).sort(function(a,b){
6478
- return a.id > b.id ? 1 : 0;
6479
- });
6480
- };
6481
-
6482
- /**
6483
- * Returns a ruleset configuration object with all current rules.
6484
- * @return A ruleset object.
6485
- * @method getRuleset
6486
- */
6487
- api.getRuleset = function() {
6488
- var ruleset = {},
6489
- i = 0,
6490
- len = rules.length;
6491
-
6492
- while (i < len){
6493
- ruleset[rules[i++].id] = 1; //by default, everything is a warning
6494
- }
6495
-
6496
- return ruleset;
6497
- };
6498
-
6499
- /**
6500
- * Returns a ruleset object based on embedded rules.
6501
- * @param {String} text A string of css containing embedded rules.
6502
- * @param {Object} ruleset A ruleset object to modify.
6503
- * @return {Object} A ruleset object.
6504
- * @method getEmbeddedRuleset
6505
- */
6506
- function applyEmbeddedRuleset(text, ruleset){
6507
- var valueMap,
6508
- embedded = text && text.match(embeddedRuleset),
6509
- rules = embedded && embedded[1];
6510
-
6511
- if (rules) {
6512
- valueMap = {
6513
- "true": 2, // true is error
6514
- "": 1, // blank is warning
6515
- "false": 0, // false is ignore
6516
-
6517
- "2": 2, // explicit error
6518
- "1": 1, // explicit warning
6519
- "0": 0 // explicit ignore
6520
- };
6521
-
6522
- rules.toLowerCase().split(",").forEach(function(rule){
6523
- var pair = rule.split(":"),
6524
- property = pair[0] || "",
6525
- value = pair[1] || "";
6526
-
6527
- ruleset[property.trim()] = valueMap[value.trim()];
6528
- });
6529
- }
6530
-
6531
- return ruleset;
6532
- }
6533
-
6534
- //-------------------------------------------------------------------------
6535
- // Formatters
6536
- //-------------------------------------------------------------------------
6537
-
6538
- /**
6539
- * Adds a new formatter to the engine.
6540
- * @param {Object} formatter The formatter to add.
6541
- * @method addFormatter
6542
- */
6543
- api.addFormatter = function(formatter) {
6544
- // formatters.push(formatter);
6545
- formatters[formatter.id] = formatter;
6546
- };
6547
-
6548
- /**
6549
- * Retrieves a formatter for use.
6550
- * @param {String} formatId The name of the format to retrieve.
6551
- * @return {Object} The formatter or undefined.
6552
- * @method getFormatter
6553
- */
6554
- api.getFormatter = function(formatId){
6555
- return formatters[formatId];
6556
- };
6557
-
6558
- /**
6559
- * Formats the results in a particular format for a single file.
6560
- * @param {Object} result The results returned from CSSLint.verify().
6561
- * @param {String} filename The filename for which the results apply.
6562
- * @param {String} formatId The name of the formatter to use.
6563
- * @param {Object} options (Optional) for special output handling.
6564
- * @return {String} A formatted string for the results.
6565
- * @method format
6566
- */
6567
- api.format = function(results, filename, formatId, options) {
6568
- var formatter = this.getFormatter(formatId),
6569
- result = null;
6570
-
6571
- if (formatter){
6572
- result = formatter.startFormat();
6573
- result += formatter.formatResults(results, filename, options || {});
6574
- result += formatter.endFormat();
6575
- }
6576
-
6577
- return result;
6578
- };
6579
-
6580
- /**
6581
- * Indicates if the given format is supported.
6582
- * @param {String} formatId The ID of the format to check.
6583
- * @return {Boolean} True if the format exists, false if not.
6584
- * @method hasFormat
6585
- */
6586
- api.hasFormat = function(formatId){
6587
- return formatters.hasOwnProperty(formatId);
6588
- };
6589
-
6590
- //-------------------------------------------------------------------------
6591
- // Verification
6592
- //-------------------------------------------------------------------------
6593
-
6594
- /**
6595
- * Starts the verification process for the given CSS text.
6596
- * @param {String} text The CSS text to verify.
6597
- * @param {Object} ruleset (Optional) List of rules to apply. If null, then
6598
- * all rules are used. If a rule has a value of 1 then it's a warning,
6599
- * a value of 2 means it's an error.
6600
- * @return {Object} Results of the verification.
6601
- * @method verify
6602
- */
6603
- api.verify = function(text, ruleset){
6604
-
6605
- var i = 0,
6606
- len = rules.length,
6607
- reporter,
6608
- lines,
6609
- report,
6610
- parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
6611
- underscoreHack: true, strict: false });
6612
-
6613
- // normalize line endings
6614
- lines = text.replace(/\n\r?/g, "$split$").split('$split$');
6615
-
6616
- if (!ruleset){
6617
- ruleset = this.getRuleset();
6618
- }
6619
-
6620
- if (embeddedRuleset.test(text)){
6621
- ruleset = applyEmbeddedRuleset(text, ruleset);
6622
- }
6623
-
6624
- reporter = new Reporter(lines, ruleset);
6625
-
6626
- ruleset.errors = 2; //always report parsing errors as errors
6627
- for (i in ruleset){
6628
- if(ruleset.hasOwnProperty(i) && ruleset[i]){
6629
- if (rules[i]){
6630
- rules[i].init(parser, reporter);
6631
- }
6632
- }
6633
- }
6634
-
6635
-
6636
- //capture most horrible error type
6637
- try {
6638
- parser.parse(text);
6639
- } catch (ex) {
6640
- reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
6641
- }
6642
-
6643
- report = {
6644
- messages : reporter.messages,
6645
- stats : reporter.stats,
6646
- ruleset : reporter.ruleset
6647
- };
6648
-
6649
- //sort by line numbers, rollups at the bottom
6650
- report.messages.sort(function (a, b){
6651
- if (a.rollup && !b.rollup){
6652
- return 1;
6653
- } else if (!a.rollup && b.rollup){
6654
- return -1;
6655
- } else {
6656
- return a.line - b.line;
6657
- }
6658
- });
6659
-
6660
- return report;
6661
- };
6662
-
6663
- //-------------------------------------------------------------------------
6664
- // Publish the API
6665
- //-------------------------------------------------------------------------
6666
-
6667
- return api;
6668
-
6669
- })();
6670
-
6671
- /*global CSSLint*/
6672
- /**
6673
- * An instance of Report is used to report results of the
6674
- * verification back to the main API.
6675
- * @class Reporter
6676
- * @constructor
6677
- * @param {String[]} lines The text lines of the source.
6678
- * @param {Object} ruleset The set of rules to work with, including if
6679
- * they are errors or warnings.
6680
- */
6681
- function Reporter(lines, ruleset){
6682
-
6683
- /**
6684
- * List of messages being reported.
6685
- * @property messages
6686
- * @type String[]
6687
- */
6688
- this.messages = [];
6689
-
6690
- /**
6691
- * List of statistics being reported.
6692
- * @property stats
6693
- * @type String[]
6694
- */
6695
- this.stats = [];
6696
-
6697
- /**
6698
- * Lines of code being reported on. Used to provide contextual information
6699
- * for messages.
6700
- * @property lines
6701
- * @type String[]
6702
- */
6703
- this.lines = lines;
6704
-
6705
- /**
6706
- * Information about the rules. Used to determine whether an issue is an
6707
- * error or warning.
6708
- * @property ruleset
6709
- * @type Object
6710
- */
6711
- this.ruleset = ruleset;
6712
- }
6713
-
6714
- Reporter.prototype = {
6715
-
6716
- //restore constructor
6717
- constructor: Reporter,
6718
-
6719
- /**
6720
- * Report an error.
6721
- * @param {String} message The message to store.
6722
- * @param {int} line The line number.
6723
- * @param {int} col The column number.
6724
- * @param {Object} rule The rule this message relates to.
6725
- * @method error
6726
- */
6727
- error: function(message, line, col, rule){
6728
- this.messages.push({
6729
- type : "error",
6730
- line : line,
6731
- col : col,
6732
- message : message,
6733
- evidence: this.lines[line-1],
6734
- rule : rule || {}
6735
- });
6736
- },
6737
-
6738
- /**
6739
- * Report an warning.
6740
- * @param {String} message The message to store.
6741
- * @param {int} line The line number.
6742
- * @param {int} col The column number.
6743
- * @param {Object} rule The rule this message relates to.
6744
- * @method warn
6745
- * @deprecated Use report instead.
6746
- */
6747
- warn: function(message, line, col, rule){
6748
- this.report(message, line, col, rule);
6749
- },
6750
-
6751
- /**
6752
- * Report an issue.
6753
- * @param {String} message The message to store.
6754
- * @param {int} line The line number.
6755
- * @param {int} col The column number.
6756
- * @param {Object} rule The rule this message relates to.
6757
- * @method report
6758
- */
6759
- report: function(message, line, col, rule){
6760
- this.messages.push({
6761
- type : this.ruleset[rule.id] == 2 ? "error" : "warning",
6762
- line : line,
6763
- col : col,
6764
- message : message,
6765
- evidence: this.lines[line-1],
6766
- rule : rule
6767
- });
6768
- },
6769
-
6770
- /**
6771
- * Report some informational text.
6772
- * @param {String} message The message to store.
6773
- * @param {int} line The line number.
6774
- * @param {int} col The column number.
6775
- * @param {Object} rule The rule this message relates to.
6776
- * @method info
6777
- */
6778
- info: function(message, line, col, rule){
6779
- this.messages.push({
6780
- type : "info",
6781
- line : line,
6782
- col : col,
6783
- message : message,
6784
- evidence: this.lines[line-1],
6785
- rule : rule
6786
- });
6787
- },
6788
-
6789
- /**
6790
- * Report some rollup error information.
6791
- * @param {String} message The message to store.
6792
- * @param {Object} rule The rule this message relates to.
6793
- * @method rollupError
6794
- */
6795
- rollupError: function(message, rule){
6796
- this.messages.push({
6797
- type : "error",
6798
- rollup : true,
6799
- message : message,
6800
- rule : rule
6801
- });
6802
- },
6803
-
6804
- /**
6805
- * Report some rollup warning information.
6806
- * @param {String} message The message to store.
6807
- * @param {Object} rule The rule this message relates to.
6808
- * @method rollupWarn
6809
- */
6810
- rollupWarn: function(message, rule){
6811
- this.messages.push({
6812
- type : "warning",
6813
- rollup : true,
6814
- message : message,
6815
- rule : rule
6816
- });
6817
- },
6818
-
6819
- /**
6820
- * Report a statistic.
6821
- * @param {String} name The name of the stat to store.
6822
- * @param {Variant} value The value of the stat.
6823
- * @method stat
6824
- */
6825
- stat: function(name, value){
6826
- this.stats[name] = value;
6827
- }
6828
- };
6829
-
6830
- //expose for testing purposes
6831
- CSSLint._Reporter = Reporter;
6832
-
6833
- /*global CSSLint*/
6834
-
6835
- /*
6836
- * Utility functions that make life easier.
6837
- */
6838
- CSSLint.Util = {
6839
- /*
6840
- * Adds all properties from supplier onto receiver,
6841
- * overwriting if the same name already exists on
6842
- * reciever.
6843
- * @param {Object} The object to receive the properties.
6844
- * @param {Object} The object to provide the properties.
6845
- * @return {Object} The receiver
6846
- */
6847
- mix: function(receiver, supplier){
6848
- var prop;
6849
-
6850
- for (prop in supplier){
6851
- if (supplier.hasOwnProperty(prop)){
6852
- receiver[prop] = supplier[prop];
6853
- }
6854
- }
6855
-
6856
- return prop;
6857
- },
6858
-
6859
- /*
6860
- * Polyfill for array indexOf() method.
6861
- * @param {Array} values The array to search.
6862
- * @param {Variant} value The value to search for.
6863
- * @return {int} The index of the value if found, -1 if not.
6864
- */
6865
- indexOf: function(values, value){
6866
- if (values.indexOf){
6867
- return values.indexOf(value);
6868
- } else {
6869
- for (var i=0, len=values.length; i < len; i++){
6870
- if (values[i] === value){
6871
- return i;
6872
- }
6873
- }
6874
- return -1;
6875
- }
6876
- },
6877
-
6878
- /*
6879
- * Polyfill for array forEach() method.
6880
- * @param {Array} values The array to operate on.
6881
- * @param {Function} func The function to call on each item.
6882
- * @return {void}
6883
- */
6884
- forEach: function(values, func) {
6885
- if (values.forEach){
6886
- return values.forEach(func);
6887
- } else {
6888
- for (var i=0, len=values.length; i < len; i++){
6889
- func(values[i], i, values);
6890
- }
6891
- }
6892
- }
6893
- };
6894
- /*global CSSLint*/
6895
- /*
6896
- * Rule: Don't use adjoining classes (.foo.bar).
6897
- */
6898
- CSSLint.addRule({
6899
-
6900
- //rule information
6901
- id: "adjoining-classes",
6902
- name: "Disallow adjoining classes",
6903
- desc: "Don't use adjoining classes.",
6904
- browsers: "IE6",
6905
-
6906
- //initialization
6907
- init: function(parser, reporter){
6908
- var rule = this;
6909
- parser.addListener("startrule", function(event){
6910
- var selectors = event.selectors,
6911
- selector,
6912
- part,
6913
- modifier,
6914
- classCount,
6915
- i, j, k;
6916
-
6917
- for (i=0; i < selectors.length; i++){
6918
- selector = selectors[i];
6919
- for (j=0; j < selector.parts.length; j++){
6920
- part = selector.parts[j];
6921
- if (part.type == parser.SELECTOR_PART_TYPE){
6922
- classCount = 0;
6923
- for (k=0; k < part.modifiers.length; k++){
6924
- modifier = part.modifiers[k];
6925
- if (modifier.type == "class"){
6926
- classCount++;
6927
- }
6928
- if (classCount > 1){
6929
- reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
6930
- }
6931
- }
6932
- }
6933
- }
6934
- }
6935
- });
6936
- }
6937
-
6938
- });
6939
- /*global CSSLint*/
6940
-
6941
- /*
6942
- * Rule: Don't use width or height when using padding or border.
6943
- */
6944
- CSSLint.addRule({
6945
-
6946
- //rule information
6947
- id: "box-model",
6948
- name: "Beware of broken box size",
6949
- desc: "Don't use width or height when using padding or border.",
6950
- browsers: "All",
6951
-
6952
- //initialization
6953
- init: function(parser, reporter){
6954
- var rule = this,
6955
- widthProperties = {
6956
- border: 1,
6957
- "border-left": 1,
6958
- "border-right": 1,
6959
- padding: 1,
6960
- "padding-left": 1,
6961
- "padding-right": 1
6962
- },
6963
- heightProperties = {
6964
- border: 1,
6965
- "border-bottom": 1,
6966
- "border-top": 1,
6967
- padding: 1,
6968
- "padding-bottom": 1,
6969
- "padding-top": 1
6970
- },
6971
- properties,
6972
- boxSizing = false;
6973
-
6974
- function startRule(){
6975
- properties = {};
6976
- boxSizing = false;
6977
- }
6978
-
6979
- function endRule(){
6980
- var prop, value;
6981
-
6982
- if (!boxSizing) {
6983
- if (properties.height){
6984
- for (prop in heightProperties){
6985
- if (heightProperties.hasOwnProperty(prop) && properties[prop]){
6986
- value = properties[prop].value;
6987
- //special case for padding
6988
- if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
6989
- reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
6990
- }
6991
- }
6992
- }
6993
- }
6994
-
6995
- if (properties.width){
6996
- for (prop in widthProperties){
6997
- if (widthProperties.hasOwnProperty(prop) && properties[prop]){
6998
- value = properties[prop].value;
6999
-
7000
- if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
7001
- reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
7002
- }
7003
- }
7004
- }
7005
- }
7006
- }
7007
- }
7008
-
7009
- parser.addListener("startrule", startRule);
7010
- parser.addListener("startfontface", startRule);
7011
- parser.addListener("startpage", startRule);
7012
- parser.addListener("startpagemargin", startRule);
7013
- parser.addListener("startkeyframerule", startRule);
7014
-
7015
- parser.addListener("property", function(event){
7016
- var name = event.property.text.toLowerCase();
7017
-
7018
- if (heightProperties[name] || widthProperties[name]){
7019
- if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
7020
- properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
7021
- }
7022
- } else {
7023
- if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
7024
- properties[name] = 1;
7025
- } else if (name == "box-sizing") {
7026
- boxSizing = true;
7027
- }
7028
- }
7029
-
7030
- });
7031
-
7032
- parser.addListener("endrule", endRule);
7033
- parser.addListener("endfontface", endRule);
7034
- parser.addListener("endpage", endRule);
7035
- parser.addListener("endpagemargin", endRule);
7036
- parser.addListener("endkeyframerule", endRule);
7037
- }
7038
-
7039
- });
7040
- /*global CSSLint*/
7041
-
7042
- /*
7043
- * Rule: box-sizing doesn't work in IE6 and IE7.
7044
- */
7045
- CSSLint.addRule({
7046
-
7047
- //rule information
7048
- id: "box-sizing",
7049
- name: "Disallow use of box-sizing",
7050
- desc: "The box-sizing properties isn't supported in IE6 and IE7.",
7051
- browsers: "IE6, IE7",
7052
- tags: ["Compatibility"],
7053
-
7054
- //initialization
7055
- init: function(parser, reporter){
7056
- var rule = this;
7057
-
7058
- parser.addListener("property", function(event){
7059
- var name = event.property.text.toLowerCase();
7060
-
7061
- if (name == "box-sizing"){
7062
- reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
7063
- }
7064
- });
7065
- }
7066
-
7067
- });
7068
- /*
7069
- * Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE
7070
- * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)
7071
- */
7072
- /*global CSSLint*/
7073
- CSSLint.addRule({
7074
-
7075
- //rule information
7076
- id: "bulletproof-font-face",
7077
- name: "Use the bulletproof @font-face syntax",
7078
- 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).",
7079
- browsers: "All",
7080
-
7081
- //initialization
7082
- init: function(parser, reporter){
7083
- var rule = this,
7084
- count = 0,
7085
- fontFaceRule = false,
7086
- firstSrc = true,
7087
- ruleFailed = false,
7088
- line, col;
7089
-
7090
- // Mark the start of a @font-face declaration so we only test properties inside it
7091
- parser.addListener("startfontface", function(event){
7092
- fontFaceRule = true;
7093
- });
7094
-
7095
- parser.addListener("property", function(event){
7096
- // If we aren't inside an @font-face declaration then just return
7097
- if (!fontFaceRule) {
7098
- return;
7099
- }
7100
-
7101
- var propertyName = event.property.toString().toLowerCase(),
7102
- value = event.value.toString();
7103
-
7104
- // Set the line and col numbers for use in the endfontface listener
7105
- line = event.line;
7106
- col = event.col;
7107
-
7108
- // This is the property that we care about, we can ignore the rest
7109
- if (propertyName === 'src') {
7110
- var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
7111
-
7112
- // We need to handle the advanced syntax with two src properties
7113
- if (!value.match(regex) && firstSrc) {
7114
- ruleFailed = true;
7115
- firstSrc = false;
7116
- } else if (value.match(regex) && !firstSrc) {
7117
- ruleFailed = false;
7118
- }
7119
- }
7120
-
7121
-
7122
- });
7123
-
7124
- // Back to normal rules that we don't need to test
7125
- parser.addListener("endfontface", function(event){
7126
- fontFaceRule = false;
7127
-
7128
- if (ruleFailed) {
7129
- reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
7130
- }
7131
- });
7132
- }
7133
- });
7134
- /*
7135
- * Rule: Include all compatible vendor prefixes to reach a wider
7136
- * range of users.
7137
- */
7138
- /*global CSSLint*/
7139
- CSSLint.addRule({
7140
-
7141
- //rule information
7142
- id: "compatible-vendor-prefixes",
7143
- name: "Require compatible vendor prefixes",
7144
- desc: "Include all compatible vendor prefixes to reach a wider range of users.",
7145
- browsers: "All",
7146
-
7147
- //initialization
7148
- init: function (parser, reporter) {
7149
- var rule = this,
7150
- compatiblePrefixes,
7151
- properties,
7152
- prop,
7153
- variations,
7154
- prefixed,
7155
- i,
7156
- len,
7157
- inKeyFrame = false,
7158
- arrayPush = Array.prototype.push,
7159
- applyTo = [];
7160
-
7161
- // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details
7162
- compatiblePrefixes = {
7163
- "animation" : "webkit moz",
7164
- "animation-delay" : "webkit moz",
7165
- "animation-direction" : "webkit moz",
7166
- "animation-duration" : "webkit moz",
7167
- "animation-fill-mode" : "webkit moz",
7168
- "animation-iteration-count" : "webkit moz",
7169
- "animation-name" : "webkit moz",
7170
- "animation-play-state" : "webkit moz",
7171
- "animation-timing-function" : "webkit moz",
7172
- "appearance" : "webkit moz",
7173
- "border-end" : "webkit moz",
7174
- "border-end-color" : "webkit moz",
7175
- "border-end-style" : "webkit moz",
7176
- "border-end-width" : "webkit moz",
7177
- "border-image" : "webkit moz o",
7178
- "border-radius" : "webkit",
7179
- "border-start" : "webkit moz",
7180
- "border-start-color" : "webkit moz",
7181
- "border-start-style" : "webkit moz",
7182
- "border-start-width" : "webkit moz",
7183
- "box-align" : "webkit moz ms",
7184
- "box-direction" : "webkit moz ms",
7185
- "box-flex" : "webkit moz ms",
7186
- "box-lines" : "webkit ms",
7187
- "box-ordinal-group" : "webkit moz ms",
7188
- "box-orient" : "webkit moz ms",
7189
- "box-pack" : "webkit moz ms",
7190
- "box-sizing" : "webkit moz",
7191
- "box-shadow" : "webkit moz",
7192
- "column-count" : "webkit moz ms",
7193
- "column-gap" : "webkit moz ms",
7194
- "column-rule" : "webkit moz ms",
7195
- "column-rule-color" : "webkit moz ms",
7196
- "column-rule-style" : "webkit moz ms",
7197
- "column-rule-width" : "webkit moz ms",
7198
- "column-width" : "webkit moz ms",
7199
- "hyphens" : "epub moz",
7200
- "line-break" : "webkit ms",
7201
- "margin-end" : "webkit moz",
7202
- "margin-start" : "webkit moz",
7203
- "marquee-speed" : "webkit wap",
7204
- "marquee-style" : "webkit wap",
7205
- "padding-end" : "webkit moz",
7206
- "padding-start" : "webkit moz",
7207
- "tab-size" : "moz o",
7208
- "text-size-adjust" : "webkit ms",
7209
- "transform" : "webkit moz ms o",
7210
- "transform-origin" : "webkit moz ms o",
7211
- "transition" : "webkit moz o",
7212
- "transition-delay" : "webkit moz o",
7213
- "transition-duration" : "webkit moz o",
7214
- "transition-property" : "webkit moz o",
7215
- "transition-timing-function" : "webkit moz o",
7216
- "user-modify" : "webkit moz",
7217
- "user-select" : "webkit moz ms",
7218
- "word-break" : "epub ms",
7219
- "writing-mode" : "epub ms"
7220
- };
7221
-
7222
-
7223
- for (prop in compatiblePrefixes) {
7224
- if (compatiblePrefixes.hasOwnProperty(prop)) {
7225
- variations = [];
7226
- prefixed = compatiblePrefixes[prop].split(' ');
7227
- for (i = 0, len = prefixed.length; i < len; i++) {
7228
- variations.push('-' + prefixed[i] + '-' + prop);
7229
- }
7230
- compatiblePrefixes[prop] = variations;
7231
- arrayPush.apply(applyTo, variations);
7232
- }
7233
- }
7234
-
7235
- parser.addListener("startrule", function () {
7236
- properties = [];
7237
- });
7238
-
7239
- parser.addListener("startkeyframes", function (event) {
7240
- inKeyFrame = event.prefix || true;
7241
- });
7242
-
7243
- parser.addListener("endkeyframes", function (event) {
7244
- inKeyFrame = false;
7245
- });
7246
-
7247
- parser.addListener("property", function (event) {
7248
- var name = event.property;
7249
- if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
7250
-
7251
- // e.g., -moz-transform is okay to be alone in @-moz-keyframes
7252
- if (!inKeyFrame || typeof inKeyFrame != "string" ||
7253
- name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
7254
- properties.push(name);
7255
- }
7256
- }
7257
- });
7258
-
7259
- parser.addListener("endrule", function (event) {
7260
- if (!properties.length) {
7261
- return;
7262
- }
7263
-
7264
- var propertyGroups = {},
7265
- i,
7266
- len,
7267
- name,
7268
- prop,
7269
- variations,
7270
- value,
7271
- full,
7272
- actual,
7273
- item,
7274
- propertiesSpecified;
7275
-
7276
- for (i = 0, len = properties.length; i < len; i++) {
7277
- name = properties[i];
7278
-
7279
- for (prop in compatiblePrefixes) {
7280
- if (compatiblePrefixes.hasOwnProperty(prop)) {
7281
- variations = compatiblePrefixes[prop];
7282
- if (CSSLint.Util.indexOf(variations, name.text) > -1) {
7283
- if (!propertyGroups[prop]) {
7284
- propertyGroups[prop] = {
7285
- full : variations.slice(0),
7286
- actual : [],
7287
- actualNodes: []
7288
- };
7289
- }
7290
- if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
7291
- propertyGroups[prop].actual.push(name.text);
7292
- propertyGroups[prop].actualNodes.push(name);
7293
- }
7294
- }
7295
- }
7296
- }
7297
- }
7298
-
7299
- for (prop in propertyGroups) {
7300
- if (propertyGroups.hasOwnProperty(prop)) {
7301
- value = propertyGroups[prop];
7302
- full = value.full;
7303
- actual = value.actual;
7304
-
7305
- if (full.length > actual.length) {
7306
- for (i = 0, len = full.length; i < len; i++) {
7307
- item = full[i];
7308
- if (CSSLint.Util.indexOf(actual, item) === -1) {
7309
- propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
7310
- reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
7311
- }
7312
- }
7313
-
7314
- }
7315
- }
7316
- }
7317
- });
7318
- }
7319
- });
7320
- /*
7321
- * Rule: Certain properties don't play well with certain display values.
7322
- * - float should not be used with inline-block
7323
- * - height, width, margin-top, margin-bottom, float should not be used with inline
7324
- * - vertical-align should not be used with block
7325
- * - margin, float should not be used with table-*
7326
- */
7327
- /*global CSSLint*/
7328
- CSSLint.addRule({
7329
-
7330
- //rule information
7331
- id: "display-property-grouping",
7332
- name: "Require properties appropriate for display",
7333
- desc: "Certain properties shouldn't be used with certain display property values.",
7334
- browsers: "All",
7335
-
7336
- //initialization
7337
- init: function(parser, reporter){
7338
- var rule = this;
7339
-
7340
- var propertiesToCheck = {
7341
- display: 1,
7342
- "float": "none",
7343
- height: 1,
7344
- width: 1,
7345
- margin: 1,
7346
- "margin-left": 1,
7347
- "margin-right": 1,
7348
- "margin-bottom": 1,
7349
- "margin-top": 1,
7350
- padding: 1,
7351
- "padding-left": 1,
7352
- "padding-right": 1,
7353
- "padding-bottom": 1,
7354
- "padding-top": 1,
7355
- "vertical-align": 1
7356
- },
7357
- properties;
7358
-
7359
- function reportProperty(name, display, msg){
7360
- if (properties[name]){
7361
- if (typeof propertiesToCheck[name] != "string" || properties[name].value.toLowerCase() != propertiesToCheck[name]){
7362
- reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
7363
- }
7364
- }
7365
- }
7366
-
7367
- function startRule(){
7368
- properties = {};
7369
- }
7370
-
7371
- function endRule(){
7372
-
7373
- var display = properties.display ? properties.display.value : null;
7374
- if (display){
7375
- switch(display){
7376
-
7377
- case "inline":
7378
- //height, width, margin-top, margin-bottom, float should not be used with inline
7379
- reportProperty("height", display);
7380
- reportProperty("width", display);
7381
- reportProperty("margin", display);
7382
- reportProperty("margin-top", display);
7383
- reportProperty("margin-bottom", display);
7384
- reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
7385
- break;
7386
-
7387
- case "block":
7388
- //vertical-align should not be used with block
7389
- reportProperty("vertical-align", display);
7390
- break;
7391
-
7392
- case "inline-block":
7393
- //float should not be used with inline-block
7394
- reportProperty("float", display);
7395
- break;
7396
-
7397
- default:
7398
- //margin, float should not be used with table
7399
- if (display.indexOf("table-") === 0){
7400
- reportProperty("margin", display);
7401
- reportProperty("margin-left", display);
7402
- reportProperty("margin-right", display);
7403
- reportProperty("margin-top", display);
7404
- reportProperty("margin-bottom", display);
7405
- reportProperty("float", display);
7406
- }
7407
-
7408
- //otherwise do nothing
7409
- }
7410
- }
7411
-
7412
- }
7413
-
7414
- parser.addListener("startrule", startRule);
7415
- parser.addListener("startfontface", startRule);
7416
- parser.addListener("startkeyframerule", startRule);
7417
- parser.addListener("startpagemargin", startRule);
7418
- parser.addListener("startpage", startRule);
7419
-
7420
- parser.addListener("property", function(event){
7421
- var name = event.property.text.toLowerCase();
7422
-
7423
- if (propertiesToCheck[name]){
7424
- properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
7425
- }
7426
- });
7427
-
7428
- parser.addListener("endrule", endRule);
7429
- parser.addListener("endfontface", endRule);
7430
- parser.addListener("endkeyframerule", endRule);
7431
- parser.addListener("endpagemargin", endRule);
7432
- parser.addListener("endpage", endRule);
7433
-
7434
- }
7435
-
7436
- });
7437
- /*
7438
- * Rule: Disallow duplicate background-images (using url).
7439
- */
7440
- /*global CSSLint*/
7441
- CSSLint.addRule({
7442
-
7443
- //rule information
7444
- id: "duplicate-background-images",
7445
- name: "Disallow duplicate background images",
7446
- desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
7447
- browsers: "All",
7448
-
7449
- //initialization
7450
- init: function(parser, reporter){
7451
- var rule = this,
7452
- stack = {};
7453
-
7454
- parser.addListener("property", function(event){
7455
- var name = event.property.text,
7456
- value = event.value,
7457
- i, len;
7458
-
7459
- if (name.match(/background/i)) {
7460
- for (i=0, len=value.parts.length; i < len; i++) {
7461
- if (value.parts[i].type == 'uri') {
7462
- if (typeof stack[value.parts[i].uri] === 'undefined') {
7463
- stack[value.parts[i].uri] = event;
7464
- }
7465
- else {
7466
- reporter.report("Background image '" + value.parts[i].uri + "' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule);
7467
- }
7468
- }
7469
- }
7470
- }
7471
- });
7472
- }
7473
- });
7474
- /*
7475
- * Rule: Duplicate properties must appear one after the other. If an already-defined
7476
- * property appears somewhere else in the rule, then it's likely an error.
7477
- */
7478
- /*global CSSLint*/
7479
- CSSLint.addRule({
7480
-
7481
- //rule information
7482
- id: "duplicate-properties",
7483
- name: "Disallow duplicate properties",
7484
- desc: "Duplicate properties must appear one after the other.",
7485
- browsers: "All",
7486
-
7487
- //initialization
7488
- init: function(parser, reporter){
7489
- var rule = this,
7490
- properties,
7491
- lastProperty;
7492
-
7493
- function startRule(event){
7494
- properties = {};
7495
- }
7496
-
7497
- parser.addListener("startrule", startRule);
7498
- parser.addListener("startfontface", startRule);
7499
- parser.addListener("startpage", startRule);
7500
- parser.addListener("startpagemargin", startRule);
7501
- parser.addListener("startkeyframerule", startRule);
7502
-
7503
- parser.addListener("property", function(event){
7504
- var property = event.property,
7505
- name = property.text.toLowerCase();
7506
-
7507
- if (properties[name] && (lastProperty != name || properties[name] == event.value.text)){
7508
- reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
7509
- }
7510
-
7511
- properties[name] = event.value.text;
7512
- lastProperty = name;
7513
-
7514
- });
7515
-
7516
-
7517
- }
7518
-
7519
- });
7520
- /*
7521
- * Rule: Style rules without any properties defined should be removed.
7522
- */
7523
- /*global CSSLint*/
7524
- CSSLint.addRule({
7525
-
7526
- //rule information
7527
- id: "empty-rules",
7528
- name: "Disallow empty rules",
7529
- desc: "Rules without any properties specified should be removed.",
7530
- browsers: "All",
7531
-
7532
- //initialization
7533
- init: function(parser, reporter){
7534
- var rule = this,
7535
- count = 0;
7536
-
7537
- parser.addListener("startrule", function(){
7538
- count=0;
7539
- });
7540
-
7541
- parser.addListener("property", function(){
7542
- count++;
7543
- });
7544
-
7545
- parser.addListener("endrule", function(event){
7546
- var selectors = event.selectors;
7547
- if (count === 0){
7548
- reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
7549
- }
7550
- });
7551
- }
7552
-
7553
- });
7554
- /*
7555
- * Rule: There should be no syntax errors. (Duh.)
7556
- */
7557
- /*global CSSLint*/
7558
- CSSLint.addRule({
7559
-
7560
- //rule information
7561
- id: "errors",
7562
- name: "Parsing Errors",
7563
- desc: "This rule looks for recoverable syntax errors.",
7564
- browsers: "All",
7565
-
7566
- //initialization
7567
- init: function(parser, reporter){
7568
- var rule = this;
7569
-
7570
- parser.addListener("error", function(event){
7571
- reporter.error(event.message, event.line, event.col, rule);
7572
- });
7573
-
7574
- }
7575
-
7576
- });
7577
-
7578
- /*global CSSLint*/
7579
- CSSLint.addRule({
7580
-
7581
- //rule information
7582
- id: "fallback-colors",
7583
- name: "Require fallback colors",
7584
- desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
7585
- browsers: "IE6,IE7,IE8",
7586
-
7587
- //initialization
7588
- init: function(parser, reporter){
7589
- var rule = this,
7590
- lastProperty,
7591
- propertiesToCheck = {
7592
- color: 1,
7593
- background: 1,
7594
- "border-color": 1,
7595
- "border-top-color": 1,
7596
- "border-right-color": 1,
7597
- "border-bottom-color": 1,
7598
- "border-left-color": 1,
7599
- border: 1,
7600
- "border-top": 1,
7601
- "border-right": 1,
7602
- "border-bottom": 1,
7603
- "border-left": 1,
7604
- "background-color": 1
7605
- },
7606
- properties;
7607
-
7608
- function startRule(event){
7609
- properties = {};
7610
- lastProperty = null;
7611
- }
7612
-
7613
- parser.addListener("startrule", startRule);
7614
- parser.addListener("startfontface", startRule);
7615
- parser.addListener("startpage", startRule);
7616
- parser.addListener("startpagemargin", startRule);
7617
- parser.addListener("startkeyframerule", startRule);
7618
-
7619
- parser.addListener("property", function(event){
7620
- var property = event.property,
7621
- name = property.text.toLowerCase(),
7622
- parts = event.value.parts,
7623
- i = 0,
7624
- colorType = "",
7625
- len = parts.length;
7626
-
7627
- if(propertiesToCheck[name]){
7628
- while(i < len){
7629
- if (parts[i].type == "color"){
7630
- if ("alpha" in parts[i] || "hue" in parts[i]){
7631
-
7632
- if (/([^\)]+)\(/.test(parts[i])){
7633
- colorType = RegExp.$1.toUpperCase();
7634
- }
7635
-
7636
- if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != "compat")){
7637
- reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
7638
- }
7639
- } else {
7640
- event.colorType = "compat";
7641
- }
7642
- }
7643
-
7644
- i++;
7645
- }
7646
- }
7647
-
7648
- lastProperty = event;
7649
- });
7650
-
7651
- }
7652
-
7653
- });
7654
- /*
7655
- * Rule: You shouldn't use more than 10 floats. If you do, there's probably
7656
- * room for some abstraction.
7657
- */
7658
- /*global CSSLint*/
7659
- CSSLint.addRule({
7660
-
7661
- //rule information
7662
- id: "floats",
7663
- name: "Disallow too many floats",
7664
- desc: "This rule tests if the float property is used too many times",
7665
- browsers: "All",
7666
-
7667
- //initialization
7668
- init: function(parser, reporter){
7669
- var rule = this;
7670
- var count = 0;
7671
-
7672
- //count how many times "float" is used
7673
- parser.addListener("property", function(event){
7674
- if (event.property.text.toLowerCase() == "float" &&
7675
- event.value.text.toLowerCase() != "none"){
7676
- count++;
7677
- }
7678
- });
7679
-
7680
- //report the results
7681
- parser.addListener("endstylesheet", function(){
7682
- reporter.stat("floats", count);
7683
- if (count >= 10){
7684
- reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
7685
- }
7686
- });
7687
- }
7688
-
7689
- });
7690
- /*
7691
- * Rule: Avoid too many @font-face declarations in the same stylesheet.
7692
- */
7693
- /*global CSSLint*/
7694
- CSSLint.addRule({
7695
-
7696
- //rule information
7697
- id: "font-faces",
7698
- name: "Don't use too many web fonts",
7699
- desc: "Too many different web fonts in the same stylesheet.",
7700
- browsers: "All",
7701
-
7702
- //initialization
7703
- init: function(parser, reporter){
7704
- var rule = this,
7705
- count = 0;
7706
-
7707
-
7708
- parser.addListener("startfontface", function(){
7709
- count++;
7710
- });
7711
-
7712
- parser.addListener("endstylesheet", function(){
7713
- if (count > 5){
7714
- reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
7715
- }
7716
- });
7717
- }
7718
-
7719
- });
7720
- /*
7721
- * Rule: You shouldn't need more than 9 font-size declarations.
7722
- */
7723
-
7724
- /*global CSSLint*/
7725
- CSSLint.addRule({
7726
-
7727
- //rule information
7728
- id: "font-sizes",
7729
- name: "Disallow too many font sizes",
7730
- desc: "Checks the number of font-size declarations.",
7731
- browsers: "All",
7732
-
7733
- //initialization
7734
- init: function(parser, reporter){
7735
- var rule = this,
7736
- count = 0;
7737
-
7738
- //check for use of "font-size"
7739
- parser.addListener("property", function(event){
7740
- if (event.property == "font-size"){
7741
- count++;
7742
- }
7743
- });
7744
-
7745
- //report the results
7746
- parser.addListener("endstylesheet", function(){
7747
- reporter.stat("font-sizes", count);
7748
- if (count >= 10){
7749
- reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
7750
- }
7751
- });
7752
- }
7753
-
7754
- });
7755
- /*
7756
- * Rule: When using a vendor-prefixed gradient, make sure to use them all.
7757
- */
7758
- /*global CSSLint*/
7759
- CSSLint.addRule({
7760
-
7761
- //rule information
7762
- id: "gradients",
7763
- name: "Require all gradient definitions",
7764
- desc: "When using a vendor-prefixed gradient, make sure to use them all.",
7765
- browsers: "All",
7766
-
7767
- //initialization
7768
- init: function(parser, reporter){
7769
- var rule = this,
7770
- gradients;
7771
-
7772
- parser.addListener("startrule", function(){
7773
- gradients = {
7774
- moz: 0,
7775
- webkit: 0,
7776
- oldWebkit: 0,
7777
- o: 0
7778
- };
7779
- });
7780
-
7781
- parser.addListener("property", function(event){
7782
-
7783
- if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
7784
- gradients[RegExp.$1] = 1;
7785
- } else if (/\-webkit\-gradient/i.test(event.value)){
7786
- gradients.oldWebkit = 1;
7787
- }
7788
-
7789
- });
7790
-
7791
- parser.addListener("endrule", function(event){
7792
- var missing = [];
7793
-
7794
- if (!gradients.moz){
7795
- missing.push("Firefox 3.6+");
7796
- }
7797
-
7798
- if (!gradients.webkit){
7799
- missing.push("Webkit (Safari 5+, Chrome)");
7800
- }
7801
-
7802
- if (!gradients.oldWebkit){
7803
- missing.push("Old Webkit (Safari 4+, Chrome)");
7804
- }
7805
-
7806
- if (!gradients.o){
7807
- missing.push("Opera 11.1+");
7808
- }
7809
-
7810
- if (missing.length && missing.length < 4){
7811
- reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
7812
- }
7813
-
7814
- });
7815
-
7816
- }
7817
-
7818
- });
7819
-
7820
- /*
7821
- * Rule: Don't use IDs for selectors.
7822
- */
7823
- /*global CSSLint*/
7824
- CSSLint.addRule({
7825
-
7826
- //rule information
7827
- id: "ids",
7828
- name: "Disallow IDs in selectors",
7829
- desc: "Selectors should not contain IDs.",
7830
- browsers: "All",
7831
-
7832
- //initialization
7833
- init: function(parser, reporter){
7834
- var rule = this;
7835
- parser.addListener("startrule", function(event){
7836
- var selectors = event.selectors,
7837
- selector,
7838
- part,
7839
- modifier,
7840
- idCount,
7841
- i, j, k;
7842
-
7843
- for (i=0; i < selectors.length; i++){
7844
- selector = selectors[i];
7845
- idCount = 0;
7846
-
7847
- for (j=0; j < selector.parts.length; j++){
7848
- part = selector.parts[j];
7849
- if (part.type == parser.SELECTOR_PART_TYPE){
7850
- for (k=0; k < part.modifiers.length; k++){
7851
- modifier = part.modifiers[k];
7852
- if (modifier.type == "id"){
7853
- idCount++;
7854
- }
7855
- }
7856
- }
7857
- }
7858
-
7859
- if (idCount == 1){
7860
- reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
7861
- } else if (idCount > 1){
7862
- reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
7863
- }
7864
- }
7865
-
7866
- });
7867
- }
7868
-
7869
- });
7870
- /*
7871
- * Rule: Don't use @import, use <link> instead.
7872
- */
7873
- /*global CSSLint*/
7874
- CSSLint.addRule({
7875
-
7876
- //rule information
7877
- id: "import",
7878
- name: "Disallow @import",
7879
- desc: "Don't use @import, use <link> instead.",
7880
- browsers: "All",
7881
-
7882
- //initialization
7883
- init: function(parser, reporter){
7884
- var rule = this;
7885
-
7886
- parser.addListener("import", function(event){
7887
- reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
7888
- });
7889
-
7890
- }
7891
-
7892
- });
7893
- /*
7894
- * Rule: Make sure !important is not overused, this could lead to specificity
7895
- * war. Display a warning on !important declarations, an error if it's
7896
- * used more at least 10 times.
7897
- */
7898
- /*global CSSLint*/
7899
- CSSLint.addRule({
7900
-
7901
- //rule information
7902
- id: "important",
7903
- name: "Disallow !important",
7904
- desc: "Be careful when using !important declaration",
7905
- browsers: "All",
7906
-
7907
- //initialization
7908
- init: function(parser, reporter){
7909
- var rule = this,
7910
- count = 0;
7911
-
7912
- //warn that important is used and increment the declaration counter
7913
- parser.addListener("property", function(event){
7914
- if (event.important === true){
7915
- count++;
7916
- reporter.report("Use of !important", event.line, event.col, rule);
7917
- }
7918
- });
7919
-
7920
- //if there are more than 10, show an error
7921
- parser.addListener("endstylesheet", function(){
7922
- reporter.stat("important", count);
7923
- if (count >= 10){
7924
- reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
7925
- }
7926
- });
7927
- }
7928
-
7929
- });
7930
- /*
7931
- * Rule: Properties should be known (listed in CSS3 specification) or
7932
- * be a vendor-prefixed property.
7933
- */
7934
- /*global CSSLint*/
7935
- CSSLint.addRule({
7936
-
7937
- //rule information
7938
- id: "known-properties",
7939
- name: "Require use of known properties",
7940
- desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
7941
- browsers: "All",
7942
-
7943
- //initialization
7944
- init: function(parser, reporter){
7945
- var rule = this;
7946
-
7947
- parser.addListener("property", function(event){
7948
- var name = event.property.text.toLowerCase();
7949
-
7950
- // the check is handled entirely by the parser-lib (https://github.com/nzakas/parser-lib)
7951
- if (event.invalid) {
7952
- reporter.report(event.invalid.message, event.line, event.col, rule);
7953
- }
7954
-
7955
- });
7956
- }
7957
-
7958
- });
7959
- /*
7960
- * Rule: outline: none or outline: 0 should only be used in a :focus rule
7961
- * and only if there are other properties in the same rule.
7962
- */
7963
- /*global CSSLint*/
7964
- CSSLint.addRule({
7965
-
7966
- //rule information
7967
- id: "outline-none",
7968
- name: "Disallow outline: none",
7969
- desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
7970
- browsers: "All",
7971
- tags: ["Accessibility"],
7972
-
7973
- //initialization
7974
- init: function(parser, reporter){
7975
- var rule = this,
7976
- lastRule;
7977
-
7978
- function startRule(event){
7979
- if (event.selectors){
7980
- lastRule = {
7981
- line: event.line,
7982
- col: event.col,
7983
- selectors: event.selectors,
7984
- propCount: 0,
7985
- outline: false
7986
- };
7987
- } else {
7988
- lastRule = null;
7989
- }
7990
- }
7991
-
7992
- function endRule(event){
7993
- if (lastRule){
7994
- if (lastRule.outline){
7995
- if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") == -1){
7996
- reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
7997
- } else if (lastRule.propCount == 1) {
7998
- reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
7999
- }
8000
- }
8001
- }
8002
- }
8003
-
8004
- parser.addListener("startrule", startRule);
8005
- parser.addListener("startfontface", startRule);
8006
- parser.addListener("startpage", startRule);
8007
- parser.addListener("startpagemargin", startRule);
8008
- parser.addListener("startkeyframerule", startRule);
8009
-
8010
- parser.addListener("property", function(event){
8011
- var name = event.property.text.toLowerCase(),
8012
- value = event.value;
8013
-
8014
- if (lastRule){
8015
- lastRule.propCount++;
8016
- if (name == "outline" && (value == "none" || value == "0")){
8017
- lastRule.outline = true;
8018
- }
8019
- }
8020
-
8021
- });
8022
-
8023
- parser.addListener("endrule", endRule);
8024
- parser.addListener("endfontface", endRule);
8025
- parser.addListener("endpage", endRule);
8026
- parser.addListener("endpagemargin", endRule);
8027
- parser.addListener("endkeyframerule", endRule);
8028
-
8029
- }
8030
-
8031
- });
8032
- /*
8033
- * Rule: Don't use classes or IDs with elements (a.foo or a#foo).
8034
- */
8035
- /*global CSSLint*/
8036
- CSSLint.addRule({
8037
-
8038
- //rule information
8039
- id: "overqualified-elements",
8040
- name: "Disallow overqualified elements",
8041
- desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
8042
- browsers: "All",
8043
-
8044
- //initialization
8045
- init: function(parser, reporter){
8046
- var rule = this,
8047
- classes = {};
8048
-
8049
- parser.addListener("startrule", function(event){
8050
- var selectors = event.selectors,
8051
- selector,
8052
- part,
8053
- modifier,
8054
- i, j, k;
8055
-
8056
- for (i=0; i < selectors.length; i++){
8057
- selector = selectors[i];
8058
-
8059
- for (j=0; j < selector.parts.length; j++){
8060
- part = selector.parts[j];
8061
- if (part.type == parser.SELECTOR_PART_TYPE){
8062
- for (k=0; k < part.modifiers.length; k++){
8063
- modifier = part.modifiers[k];
8064
- if (part.elementName && modifier.type == "id"){
8065
- reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
8066
- } else if (modifier.type == "class"){
8067
-
8068
- if (!classes[modifier]){
8069
- classes[modifier] = [];
8070
- }
8071
- classes[modifier].push({ modifier: modifier, part: part });
8072
- }
8073
- }
8074
- }
8075
- }
8076
- }
8077
- });
8078
-
8079
- parser.addListener("endstylesheet", function(){
8080
-
8081
- var prop;
8082
- for (prop in classes){
8083
- if (classes.hasOwnProperty(prop)){
8084
-
8085
- //one use means that this is overqualified
8086
- if (classes[prop].length == 1 && classes[prop][0].part.elementName){
8087
- reporter.report("Element (" + classes[prop][0].part + ") is overqualified, just use " + classes[prop][0].modifier + " without element name.", classes[prop][0].part.line, classes[prop][0].part.col, rule);
8088
- }
8089
- }
8090
- }
8091
- });
8092
- }
8093
-
8094
- });
8095
- /*
8096
- * Rule: Headings (h1-h6) should not be qualified (namespaced).
8097
- */
8098
- /*global CSSLint*/
8099
- CSSLint.addRule({
8100
-
8101
- //rule information
8102
- id: "qualified-headings",
8103
- name: "Disallow qualified headings",
8104
- desc: "Headings should not be qualified (namespaced).",
8105
- browsers: "All",
8106
-
8107
- //initialization
8108
- init: function(parser, reporter){
8109
- var rule = this;
8110
-
8111
- parser.addListener("startrule", function(event){
8112
- var selectors = event.selectors,
8113
- selector,
8114
- part,
8115
- i, j;
8116
-
8117
- for (i=0; i < selectors.length; i++){
8118
- selector = selectors[i];
8119
-
8120
- for (j=0; j < selector.parts.length; j++){
8121
- part = selector.parts[j];
8122
- if (part.type == parser.SELECTOR_PART_TYPE){
8123
- if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
8124
- reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
8125
- }
8126
- }
8127
- }
8128
- }
8129
- });
8130
- }
8131
-
8132
- });
8133
- /*
8134
- * Rule: Selectors that look like regular expressions are slow and should be avoided.
8135
- */
8136
- /*global CSSLint*/
8137
- CSSLint.addRule({
8138
-
8139
- //rule information
8140
- id: "regex-selectors",
8141
- name: "Disallow selectors that look like regexs",
8142
- desc: "Selectors that look like regular expressions are slow and should be avoided.",
8143
- browsers: "All",
8144
-
8145
- //initialization
8146
- init: function(parser, reporter){
8147
- var rule = this;
8148
-
8149
- parser.addListener("startrule", function(event){
8150
- var selectors = event.selectors,
8151
- selector,
8152
- part,
8153
- modifier,
8154
- i, j, k;
8155
-
8156
- for (i=0; i < selectors.length; i++){
8157
- selector = selectors[i];
8158
- for (j=0; j < selector.parts.length; j++){
8159
- part = selector.parts[j];
8160
- if (part.type == parser.SELECTOR_PART_TYPE){
8161
- for (k=0; k < part.modifiers.length; k++){
8162
- modifier = part.modifiers[k];
8163
- if (modifier.type == "attribute"){
8164
- if (/([\~\|\^\$\*]=)/.test(modifier)){
8165
- reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
8166
- }
8167
- }
8168
-
8169
- }
8170
- }
8171
- }
8172
- }
8173
- });
8174
- }
8175
-
8176
- });
8177
- /*
8178
- * Rule: Total number of rules should not exceed x.
8179
- */
8180
- /*global CSSLint*/
8181
- CSSLint.addRule({
8182
-
8183
- //rule information
8184
- id: "rules-count",
8185
- name: "Rules Count",
8186
- desc: "Track how many rules there are.",
8187
- browsers: "All",
8188
-
8189
- //initialization
8190
- init: function(parser, reporter){
8191
- var rule = this,
8192
- count = 0;
8193
-
8194
- //count each rule
8195
- parser.addListener("startrule", function(){
8196
- count++;
8197
- });
8198
-
8199
- parser.addListener("endstylesheet", function(){
8200
- reporter.stat("rule-count", count);
8201
- });
8202
- }
8203
-
8204
- });
8205
- /*
8206
- * Rule: Warn people with approaching the IE 4095 limit
8207
- */
8208
- /*global CSSLint*/
8209
- CSSLint.addRule({
8210
-
8211
- //rule information
8212
- id: "selector-max-approaching",
8213
- name: "Warn when approaching the 4095 selector limit for IE",
8214
- desc: "Will warn when selector count is >= 3800 selectors.",
8215
- browsers: "IE",
8216
-
8217
- //initialization
8218
- init: function(parser, reporter) {
8219
- var rule = this, count = 0;
8220
-
8221
- parser.addListener('startrule', function(event) {
8222
- count += event.selectors.length;
8223
- });
8224
-
8225
- parser.addListener("endstylesheet", function() {
8226
- if (count >= 3800) {
8227
- reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
8228
- }
8229
- });
8230
- }
8231
-
8232
- });
8233
-
8234
- /*
8235
- * Rule: Warn people past the IE 4095 limit
8236
- */
8237
- /*global CSSLint*/
8238
- CSSLint.addRule({
8239
-
8240
- //rule information
8241
- id: "selector-max",
8242
- name: "Error when past the 4095 selector limit for IE",
8243
- desc: "Will error when selector count is > 4095.",
8244
- browsers: "IE",
8245
-
8246
- //initialization
8247
- init: function(parser, reporter){
8248
- var rule = this, count = 0;
8249
-
8250
- parser.addListener('startrule',function(event) {
8251
- count += event.selectors.length;
8252
- });
8253
-
8254
- parser.addListener("endstylesheet", function() {
8255
- if (count > 4095) {
8256
- reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
8257
- }
8258
- });
8259
- }
8260
-
8261
- });
8262
- /*
8263
- * Rule: Use shorthand properties where possible.
8264
- *
8265
- */
8266
- /*global CSSLint*/
8267
- CSSLint.addRule({
8268
-
8269
- //rule information
8270
- id: "shorthand",
8271
- name: "Require shorthand properties",
8272
- desc: "Use shorthand properties where possible.",
8273
- browsers: "All",
8274
-
8275
- //initialization
8276
- init: function(parser, reporter){
8277
- var rule = this,
8278
- prop, i, len,
8279
- propertiesToCheck = {},
8280
- properties,
8281
- mapping = {
8282
- "margin": [
8283
- "margin-top",
8284
- "margin-bottom",
8285
- "margin-left",
8286
- "margin-right"
8287
- ],
8288
- "padding": [
8289
- "padding-top",
8290
- "padding-bottom",
8291
- "padding-left",
8292
- "padding-right"
8293
- ]
8294
- };
8295
-
8296
- //initialize propertiesToCheck
8297
- for (prop in mapping){
8298
- if (mapping.hasOwnProperty(prop)){
8299
- for (i=0, len=mapping[prop].length; i < len; i++){
8300
- propertiesToCheck[mapping[prop][i]] = prop;
8301
- }
8302
- }
8303
- }
8304
-
8305
- function startRule(event){
8306
- properties = {};
8307
- }
8308
-
8309
- //event handler for end of rules
8310
- function endRule(event){
8311
-
8312
- var prop, i, len, total;
8313
-
8314
- //check which properties this rule has
8315
- for (prop in mapping){
8316
- if (mapping.hasOwnProperty(prop)){
8317
- total=0;
8318
-
8319
- for (i=0, len=mapping[prop].length; i < len; i++){
8320
- total += properties[mapping[prop][i]] ? 1 : 0;
8321
- }
8322
-
8323
- if (total == mapping[prop].length){
8324
- reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
8325
- }
8326
- }
8327
- }
8328
- }
8329
-
8330
- parser.addListener("startrule", startRule);
8331
- parser.addListener("startfontface", startRule);
8332
-
8333
- //check for use of "font-size"
8334
- parser.addListener("property", function(event){
8335
- var name = event.property.toString().toLowerCase(),
8336
- value = event.value.parts[0].value;
8337
-
8338
- if (propertiesToCheck[name]){
8339
- properties[name] = 1;
8340
- }
8341
- });
8342
-
8343
- parser.addListener("endrule", endRule);
8344
- parser.addListener("endfontface", endRule);
8345
-
8346
- }
8347
-
8348
- });
8349
- /*
8350
- * Rule: Don't use properties with a star prefix.
8351
- *
8352
- */
8353
- /*global CSSLint*/
8354
- CSSLint.addRule({
8355
-
8356
- //rule information
8357
- id: "star-property-hack",
8358
- name: "Disallow properties with a star prefix",
8359
- desc: "Checks for the star property hack (targets IE6/7)",
8360
- browsers: "All",
8361
-
8362
- //initialization
8363
- init: function(parser, reporter){
8364
- var rule = this;
8365
-
8366
- //check if property name starts with "*"
8367
- parser.addListener("property", function(event){
8368
- var property = event.property;
8369
-
8370
- if (property.hack == "*") {
8371
- reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
8372
- }
8373
- });
8374
- }
8375
- });
8376
- /*
8377
- * Rule: Don't use text-indent for image replacement if you need to support rtl.
8378
- *
8379
- */
8380
- /*global CSSLint*/
8381
- CSSLint.addRule({
8382
-
8383
- //rule information
8384
- id: "text-indent",
8385
- name: "Disallow negative text-indent",
8386
- desc: "Checks for text indent less than -99px",
8387
- browsers: "All",
8388
-
8389
- //initialization
8390
- init: function(parser, reporter){
8391
- var rule = this,
8392
- textIndent,
8393
- direction;
8394
-
8395
-
8396
- function startRule(event){
8397
- textIndent = false;
8398
- direction = "inherit";
8399
- }
8400
-
8401
- //event handler for end of rules
8402
- function endRule(event){
8403
- if (textIndent && direction != "ltr"){
8404
- 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);
8405
- }
8406
- }
8407
-
8408
- parser.addListener("startrule", startRule);
8409
- parser.addListener("startfontface", startRule);
8410
-
8411
- //check for use of "font-size"
8412
- parser.addListener("property", function(event){
8413
- var name = event.property.toString().toLowerCase(),
8414
- value = event.value;
8415
-
8416
- if (name == "text-indent" && value.parts[0].value < -99){
8417
- textIndent = event.property;
8418
- } else if (name == "direction" && value == "ltr"){
8419
- direction = "ltr";
8420
- }
8421
- });
8422
-
8423
- parser.addListener("endrule", endRule);
8424
- parser.addListener("endfontface", endRule);
8425
-
8426
- }
8427
-
8428
- });
8429
- /*
8430
- * Rule: Don't use properties with a underscore prefix.
8431
- *
8432
- */
8433
- /*global CSSLint*/
8434
- CSSLint.addRule({
8435
-
8436
- //rule information
8437
- id: "underscore-property-hack",
8438
- name: "Disallow properties with an underscore prefix",
8439
- desc: "Checks for the underscore property hack (targets IE6)",
8440
- browsers: "All",
8441
-
8442
- //initialization
8443
- init: function(parser, reporter){
8444
- var rule = this;
8445
-
8446
- //check if property name starts with "_"
8447
- parser.addListener("property", function(event){
8448
- var property = event.property;
8449
-
8450
- if (property.hack == "_") {
8451
- reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
8452
- }
8453
- });
8454
- }
8455
- });
8456
- /*
8457
- * Rule: Headings (h1-h6) should be defined only once.
8458
- */
8459
- /*global CSSLint*/
8460
- CSSLint.addRule({
8461
-
8462
- //rule information
8463
- id: "unique-headings",
8464
- name: "Headings should only be defined once",
8465
- desc: "Headings should be defined only once.",
8466
- browsers: "All",
8467
-
8468
- //initialization
8469
- init: function(parser, reporter){
8470
- var rule = this;
8471
-
8472
- var headings = {
8473
- h1: 0,
8474
- h2: 0,
8475
- h3: 0,
8476
- h4: 0,
8477
- h5: 0,
8478
- h6: 0
8479
- };
8480
-
8481
- parser.addListener("startrule", function(event){
8482
- var selectors = event.selectors,
8483
- selector,
8484
- part,
8485
- pseudo,
8486
- i, j;
8487
-
8488
- for (i=0; i < selectors.length; i++){
8489
- selector = selectors[i];
8490
- part = selector.parts[selector.parts.length-1];
8491
-
8492
- if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){
8493
-
8494
- for (j=0; j < part.modifiers.length; j++){
8495
- if (part.modifiers[j].type == "pseudo"){
8496
- pseudo = true;
8497
- break;
8498
- }
8499
- }
8500
-
8501
- if (!pseudo){
8502
- headings[RegExp.$1]++;
8503
- if (headings[RegExp.$1] > 1) {
8504
- reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
8505
- }
8506
- }
8507
- }
8508
- }
8509
- });
8510
-
8511
- parser.addListener("endstylesheet", function(event){
8512
- var prop,
8513
- messages = [];
8514
-
8515
- for (prop in headings){
8516
- if (headings.hasOwnProperty(prop)){
8517
- if (headings[prop] > 1){
8518
- messages.push(headings[prop] + " " + prop + "s");
8519
- }
8520
- }
8521
- }
8522
-
8523
- if (messages.length){
8524
- reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
8525
- }
8526
- });
8527
- }
8528
-
8529
- });
8530
- /*
8531
- * Rule: Don't use universal selector because it's slow.
8532
- */
8533
- /*global CSSLint*/
8534
- CSSLint.addRule({
8535
-
8536
- //rule information
8537
- id: "universal-selector",
8538
- name: "Disallow universal selector",
8539
- desc: "The universal selector (*) is known to be slow.",
8540
- browsers: "All",
8541
-
8542
- //initialization
8543
- init: function(parser, reporter){
8544
- var rule = this;
8545
-
8546
- parser.addListener("startrule", function(event){
8547
- var selectors = event.selectors,
8548
- selector,
8549
- part,
8550
- modifier,
8551
- i, j, k;
8552
-
8553
- for (i=0; i < selectors.length; i++){
8554
- selector = selectors[i];
8555
-
8556
- part = selector.parts[selector.parts.length-1];
8557
- if (part.elementName == "*"){
8558
- reporter.report(rule.desc, part.line, part.col, rule);
8559
- }
8560
- }
8561
- });
8562
- }
8563
-
8564
- });
8565
- /*
8566
- * Rule: Don't use unqualified attribute selectors because they're just like universal selectors.
8567
- */
8568
- /*global CSSLint*/
8569
- CSSLint.addRule({
8570
-
8571
- //rule information
8572
- id: "unqualified-attributes",
8573
- name: "Disallow unqualified attribute selectors",
8574
- desc: "Unqualified attribute selectors are known to be slow.",
8575
- browsers: "All",
8576
-
8577
- //initialization
8578
- init: function(parser, reporter){
8579
- var rule = this;
8580
-
8581
- parser.addListener("startrule", function(event){
8582
-
8583
- var selectors = event.selectors,
8584
- selector,
8585
- part,
8586
- modifier,
8587
- i, j, k;
8588
-
8589
- for (i=0; i < selectors.length; i++){
8590
- selector = selectors[i];
8591
-
8592
- part = selector.parts[selector.parts.length-1];
8593
- if (part.type == parser.SELECTOR_PART_TYPE){
8594
- for (k=0; k < part.modifiers.length; k++){
8595
- modifier = part.modifiers[k];
8596
- if (modifier.type == "attribute" && (!part.elementName || part.elementName == "*")){
8597
- reporter.report(rule.desc, part.line, part.col, rule);
8598
- }
8599
- }
8600
- }
8601
-
8602
- }
8603
- });
8604
- }
8605
-
8606
- });
8607
- /*
8608
- * Rule: When using a vendor-prefixed property, make sure to
8609
- * include the standard one.
8610
- */
8611
- /*global CSSLint*/
8612
- CSSLint.addRule({
8613
-
8614
- //rule information
8615
- id: "vendor-prefix",
8616
- name: "Require standard property with vendor prefix",
8617
- desc: "When using a vendor-prefixed property, make sure to include the standard one.",
8618
- browsers: "All",
8619
-
8620
- //initialization
8621
- init: function(parser, reporter){
8622
- var rule = this,
8623
- properties,
8624
- num,
8625
- propertiesToCheck = {
8626
- "-webkit-border-radius": "border-radius",
8627
- "-webkit-border-top-left-radius": "border-top-left-radius",
8628
- "-webkit-border-top-right-radius": "border-top-right-radius",
8629
- "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
8630
- "-webkit-border-bottom-right-radius": "border-bottom-right-radius",
8631
-
8632
- "-o-border-radius": "border-radius",
8633
- "-o-border-top-left-radius": "border-top-left-radius",
8634
- "-o-border-top-right-radius": "border-top-right-radius",
8635
- "-o-border-bottom-left-radius": "border-bottom-left-radius",
8636
- "-o-border-bottom-right-radius": "border-bottom-right-radius",
8637
-
8638
- "-moz-border-radius": "border-radius",
8639
- "-moz-border-radius-topleft": "border-top-left-radius",
8640
- "-moz-border-radius-topright": "border-top-right-radius",
8641
- "-moz-border-radius-bottomleft": "border-bottom-left-radius",
8642
- "-moz-border-radius-bottomright": "border-bottom-right-radius",
8643
-
8644
- "-moz-column-count": "column-count",
8645
- "-webkit-column-count": "column-count",
8646
-
8647
- "-moz-column-gap": "column-gap",
8648
- "-webkit-column-gap": "column-gap",
8649
-
8650
- "-moz-column-rule": "column-rule",
8651
- "-webkit-column-rule": "column-rule",
8652
-
8653
- "-moz-column-rule-style": "column-rule-style",
8654
- "-webkit-column-rule-style": "column-rule-style",
8655
-
8656
- "-moz-column-rule-color": "column-rule-color",
8657
- "-webkit-column-rule-color": "column-rule-color",
8658
-
8659
- "-moz-column-rule-width": "column-rule-width",
8660
- "-webkit-column-rule-width": "column-rule-width",
8661
-
8662
- "-moz-column-width": "column-width",
8663
- "-webkit-column-width": "column-width",
8664
-
8665
- "-webkit-column-span": "column-span",
8666
- "-webkit-columns": "columns",
8667
-
8668
- "-moz-box-shadow": "box-shadow",
8669
- "-webkit-box-shadow": "box-shadow",
8670
-
8671
- "-moz-transform" : "transform",
8672
- "-webkit-transform" : "transform",
8673
- "-o-transform" : "transform",
8674
- "-ms-transform" : "transform",
8675
-
8676
- "-moz-transform-origin" : "transform-origin",
8677
- "-webkit-transform-origin" : "transform-origin",
8678
- "-o-transform-origin" : "transform-origin",
8679
- "-ms-transform-origin" : "transform-origin",
8680
-
8681
- "-moz-box-sizing" : "box-sizing",
8682
- "-webkit-box-sizing" : "box-sizing",
8683
-
8684
- "-moz-user-select" : "user-select",
8685
- "-khtml-user-select" : "user-select",
8686
- "-webkit-user-select" : "user-select"
8687
- };
8688
-
8689
- //event handler for beginning of rules
8690
- function startRule(){
8691
- properties = {};
8692
- num=1;
8693
- }
8694
-
8695
- //event handler for end of rules
8696
- function endRule(event){
8697
- var prop,
8698
- i, len,
8699
- standard,
8700
- needed,
8701
- actual,
8702
- needsStandard = [];
8703
-
8704
- for (prop in properties){
8705
- if (propertiesToCheck[prop]){
8706
- needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
8707
- }
8708
- }
8709
-
8710
- for (i=0, len=needsStandard.length; i < len; i++){
8711
- needed = needsStandard[i].needed;
8712
- actual = needsStandard[i].actual;
8713
-
8714
- if (!properties[needed]){
8715
- reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
8716
- } else {
8717
- //make sure standard property is last
8718
- if (properties[needed][0].pos < properties[actual][0].pos){
8719
- reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
8720
- }
8721
- }
8722
- }
8723
-
8724
- }
8725
-
8726
- parser.addListener("startrule", startRule);
8727
- parser.addListener("startfontface", startRule);
8728
- parser.addListener("startpage", startRule);
8729
- parser.addListener("startpagemargin", startRule);
8730
- parser.addListener("startkeyframerule", startRule);
8731
-
8732
- parser.addListener("property", function(event){
8733
- var name = event.property.text.toLowerCase();
8734
-
8735
- if (!properties[name]){
8736
- properties[name] = [];
8737
- }
8738
-
8739
- properties[name].push({ name: event.property, value : event.value, pos:num++ });
8740
- });
8741
-
8742
- parser.addListener("endrule", endRule);
8743
- parser.addListener("endfontface", endRule);
8744
- parser.addListener("endpage", endRule);
8745
- parser.addListener("endpagemargin", endRule);
8746
- parser.addListener("endkeyframerule", endRule);
8747
- }
8748
-
8749
- });
8750
- /*
8751
- * Rule: You don't need to specify units when a value is 0.
8752
- */
8753
- /*global CSSLint*/
8754
- CSSLint.addRule({
8755
-
8756
- //rule information
8757
- id: "zero-units",
8758
- name: "Disallow units for 0 values",
8759
- desc: "You don't need to specify units when a value is 0.",
8760
- browsers: "All",
8761
-
8762
- //initialization
8763
- init: function(parser, reporter){
8764
- var rule = this;
8765
-
8766
- //count how many times "float" is used
8767
- parser.addListener("property", function(event){
8768
- var parts = event.value.parts,
8769
- i = 0,
8770
- len = parts.length;
8771
-
8772
- while(i < len){
8773
- if ((parts[i].units || parts[i].type == "percentage") && parts[i].value === 0 && parts[i].type != "time"){
8774
- reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
8775
- }
8776
- i++;
8777
- }
8778
-
8779
- });
8780
-
8781
- }
8782
-
8783
- });
8784
- /*global CSSLint*/
8785
- (function() {
8786
-
8787
- /**
8788
- * Replace special characters before write to output.
8789
- *
8790
- * Rules:
8791
- * - single quotes is the escape sequence for double-quotes
8792
- * - &amp; is the escape sequence for &
8793
- * - &lt; is the escape sequence for <
8794
- * - &gt; is the escape sequence for >
8795
- *
8796
- * @param {String} message to escape
8797
- * @return escaped message as {String}
8798
- */
8799
- var xmlEscape = function(str) {
8800
- if (!str || str.constructor !== String) {
8801
- return "";
8802
- }
8803
-
8804
- return str.replace(/[\"&><]/g, function(match) {
8805
- switch (match) {
8806
- case "\"":
8807
- return "&quot;";
8808
- case "&":
8809
- return "&amp;";
8810
- case "<":
8811
- return "&lt;";
8812
- case ">":
8813
- return "&gt;";
8814
- }
8815
- });
8816
- };
8817
-
8818
- CSSLint.addFormatter({
8819
- //format information
8820
- id: "checkstyle-xml",
8821
- name: "Checkstyle XML format",
8822
-
8823
- /**
8824
- * Return opening root XML tag.
8825
- * @return {String} to prepend before all results
8826
- */
8827
- startFormat: function(){
8828
- return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
8829
- },
8830
-
8831
- /**
8832
- * Return closing root XML tag.
8833
- * @return {String} to append after all results
8834
- */
8835
- endFormat: function(){
8836
- return "</checkstyle>";
8837
- },
8838
-
8839
- /**
8840
- * Returns message when there is a file read error.
8841
- * @param {String} filename The name of the file that caused the error.
8842
- * @param {String} message The error message
8843
- * @return {String} The error message.
8844
- */
8845
- readError: function(filename, message) {
8846
- return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
8847
- },
8848
-
8849
- /**
8850
- * Given CSS Lint results for a file, return output for this format.
8851
- * @param results {Object} with error and warning messages
8852
- * @param filename {String} relative file path
8853
- * @param options {Object} (UNUSED for now) specifies special handling of output
8854
- * @return {String} output for results
8855
- */
8856
- formatResults: function(results, filename, options) {
8857
- var messages = results.messages,
8858
- output = [];
8859
-
8860
- /**
8861
- * Generate a source string for a rule.
8862
- * Checkstyle source strings usually resemble Java class names e.g
8863
- * net.csslint.SomeRuleName
8864
- * @param {Object} rule
8865
- * @return rule source as {String}
8866
- */
8867
- var generateSource = function(rule) {
8868
- if (!rule || !('name' in rule)) {
8869
- return "";
8870
- }
8871
- return 'net.csslint.' + rule.name.replace(/\s/g,'');
8872
- };
8873
-
8874
-
8875
-
8876
- if (messages.length > 0) {
8877
- output.push("<file name=\""+filename+"\">");
8878
- CSSLint.Util.forEach(messages, function (message, i) {
8879
- //ignore rollups for now
8880
- if (!message.rollup) {
8881
- output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
8882
- " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
8883
- }
8884
- });
8885
- output.push("</file>");
8886
- }
8887
-
8888
- return output.join("");
8889
- }
8890
- });
8891
-
8892
- }());
8893
- /*global CSSLint*/
8894
- CSSLint.addFormatter({
8895
- //format information
8896
- id: "compact",
8897
- name: "Compact, 'porcelain' format",
8898
-
8899
- /**
8900
- * Return content to be printed before all file results.
8901
- * @return {String} to prepend before all results
8902
- */
8903
- startFormat: function() {
8904
- return "";
8905
- },
8906
-
8907
- /**
8908
- * Return content to be printed after all file results.
8909
- * @return {String} to append after all results
8910
- */
8911
- endFormat: function() {
8912
- return "";
8913
- },
8914
-
8915
- /**
8916
- * Given CSS Lint results for a file, return output for this format.
8917
- * @param results {Object} with error and warning messages
8918
- * @param filename {String} relative file path
8919
- * @param options {Object} (Optional) specifies special handling of output
8920
- * @return {String} output for results
8921
- */
8922
- formatResults: function(results, filename, options) {
8923
- var messages = results.messages,
8924
- output = "";
8925
- options = options || {};
8926
-
8927
- /**
8928
- * Capitalize and return given string.
8929
- * @param str {String} to capitalize
8930
- * @return {String} capitalized
8931
- */
8932
- var capitalize = function(str) {
8933
- return str.charAt(0).toUpperCase() + str.slice(1);
8934
- };
8935
-
8936
- if (messages.length === 0) {
8937
- return options.quiet ? "" : filename + ": Lint Free!";
8938
- }
8939
-
8940
- CSSLint.Util.forEach(messages, function(message, i) {
8941
- if (message.rollup) {
8942
- output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n";
8943
- } else {
8944
- output += filename + ": " + "line " + message.line +
8945
- ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + "\n";
8946
- }
8947
- });
8948
-
8949
- return output;
8950
- }
8951
- });
8952
- /*global CSSLint*/
8953
- CSSLint.addFormatter({
8954
- //format information
8955
- id: "csslint-xml",
8956
- name: "CSSLint XML format",
8957
-
8958
- /**
8959
- * Return opening root XML tag.
8960
- * @return {String} to prepend before all results
8961
- */
8962
- startFormat: function(){
8963
- return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
8964
- },
8965
-
8966
- /**
8967
- * Return closing root XML tag.
8968
- * @return {String} to append after all results
8969
- */
8970
- endFormat: function(){
8971
- return "</csslint>";
8972
- },
8973
-
8974
- /**
8975
- * Given CSS Lint results for a file, return output for this format.
8976
- * @param results {Object} with error and warning messages
8977
- * @param filename {String} relative file path
8978
- * @param options {Object} (UNUSED for now) specifies special handling of output
8979
- * @return {String} output for results
8980
- */
8981
- formatResults: function(results, filename, options) {
8982
- var messages = results.messages,
8983
- output = [];
8984
-
8985
- /**
8986
- * Replace special characters before write to output.
8987
- *
8988
- * Rules:
8989
- * - single quotes is the escape sequence for double-quotes
8990
- * - &amp; is the escape sequence for &
8991
- * - &lt; is the escape sequence for <
8992
- * - &gt; is the escape sequence for >
8993
- *
8994
- * @param {String} message to escape
8995
- * @return escaped message as {String}
8996
- */
8997
- var escapeSpecialCharacters = function(str) {
8998
- if (!str || str.constructor !== String) {
8999
- return "";
9000
- }
9001
- return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9002
- };
9003
-
9004
- if (messages.length > 0) {
9005
- output.push("<file name=\""+filename+"\">");
9006
- CSSLint.Util.forEach(messages, function (message, i) {
9007
- if (message.rollup) {
9008
- output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
9009
- } else {
9010
- output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
9011
- " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
9012
- }
9013
- });
9014
- output.push("</file>");
9015
- }
9016
-
9017
- return output.join("");
9018
- }
9019
- });
9020
- /*global CSSLint*/
9021
- CSSLint.addFormatter({
9022
- //format information
9023
- id: "junit-xml",
9024
- name: "JUNIT XML format",
9025
-
9026
- /**
9027
- * Return opening root XML tag.
9028
- * @return {String} to prepend before all results
9029
- */
9030
- startFormat: function(){
9031
- return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
9032
- },
9033
-
9034
- /**
9035
- * Return closing root XML tag.
9036
- * @return {String} to append after all results
9037
- */
9038
- endFormat: function() {
9039
- return "</testsuites>";
9040
- },
9041
-
9042
- /**
9043
- * Given CSS Lint results for a file, return output for this format.
9044
- * @param results {Object} with error and warning messages
9045
- * @param filename {String} relative file path
9046
- * @param options {Object} (UNUSED for now) specifies special handling of output
9047
- * @return {String} output for results
9048
- */
9049
- formatResults: function(results, filename, options) {
9050
-
9051
- var messages = results.messages,
9052
- output = [],
9053
- tests = {
9054
- 'error': 0,
9055
- 'failure': 0
9056
- };
9057
-
9058
- /**
9059
- * Generate a source string for a rule.
9060
- * JUNIT source strings usually resemble Java class names e.g
9061
- * net.csslint.SomeRuleName
9062
- * @param {Object} rule
9063
- * @return rule source as {String}
9064
- */
9065
- var generateSource = function(rule) {
9066
- if (!rule || !('name' in rule)) {
9067
- return "";
9068
- }
9069
- return 'net.csslint.' + rule.name.replace(/\s/g,'');
9070
- };
9071
-
9072
- /**
9073
- * Replace special characters before write to output.
9074
- *
9075
- * Rules:
9076
- * - single quotes is the escape sequence for double-quotes
9077
- * - &lt; is the escape sequence for <
9078
- * - &gt; is the escape sequence for >
9079
- *
9080
- * @param {String} message to escape
9081
- * @return escaped message as {String}
9082
- */
9083
- var escapeSpecialCharacters = function(str) {
9084
-
9085
- if (!str || str.constructor !== String) {
9086
- return "";
9087
- }
9088
-
9089
- return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9090
-
9091
- };
9092
-
9093
- if (messages.length > 0) {
9094
-
9095
- messages.forEach(function (message, i) {
9096
-
9097
- // since junit has no warning class
9098
- // all issues as errors
9099
- var type = message.type === 'warning' ? 'error' : message.type;
9100
-
9101
- //ignore rollups for now
9102
- if (!message.rollup) {
9103
-
9104
- // build the test case seperately, once joined
9105
- // we'll add it to a custom array filtered by type
9106
- output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
9107
- output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ':' + message.col + ':' + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">");
9108
- output.push("</testcase>");
9109
-
9110
- tests[type] += 1;
9111
-
9112
- }
9113
-
9114
- });
9115
-
9116
- output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
9117
- output.push("</testsuite>");
9118
-
9119
- }
9120
-
9121
- return output.join("");
9122
-
9123
- }
9124
- });
9125
- /*global CSSLint*/
9126
- CSSLint.addFormatter({
9127
- //format information
9128
- id: "lint-xml",
9129
- name: "Lint XML format",
9130
-
9131
- /**
9132
- * Return opening root XML tag.
9133
- * @return {String} to prepend before all results
9134
- */
9135
- startFormat: function(){
9136
- return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
9137
- },
9138
-
9139
- /**
9140
- * Return closing root XML tag.
9141
- * @return {String} to append after all results
9142
- */
9143
- endFormat: function(){
9144
- return "</lint>";
9145
- },
9146
-
9147
- /**
9148
- * Given CSS Lint results for a file, return output for this format.
9149
- * @param results {Object} with error and warning messages
9150
- * @param filename {String} relative file path
9151
- * @param options {Object} (UNUSED for now) specifies special handling of output
9152
- * @return {String} output for results
9153
- */
9154
- formatResults: function(results, filename, options) {
9155
- var messages = results.messages,
9156
- output = [];
9157
-
9158
- /**
9159
- * Replace special characters before write to output.
9160
- *
9161
- * Rules:
9162
- * - single quotes is the escape sequence for double-quotes
9163
- * - &amp; is the escape sequence for &
9164
- * - &lt; is the escape sequence for <
9165
- * - &gt; is the escape sequence for >
9166
- *
9167
- * @param {String} message to escape
9168
- * @return escaped message as {String}
9169
- */
9170
- var escapeSpecialCharacters = function(str) {
9171
- if (!str || str.constructor !== String) {
9172
- return "";
9173
- }
9174
- return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9175
- };
9176
-
9177
- if (messages.length > 0) {
9178
-
9179
- output.push("<file name=\""+filename+"\">");
9180
- CSSLint.Util.forEach(messages, function (message, i) {
9181
- if (message.rollup) {
9182
- output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
9183
- } else {
9184
- output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
9185
- " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
9186
- }
9187
- });
9188
- output.push("</file>");
9189
- }
9190
-
9191
- return output.join("");
9192
- }
9193
- });
9194
- /*global CSSLint*/
9195
- CSSLint.addFormatter({
9196
- //format information
9197
- id: "text",
9198
- name: "Plain Text",
9199
-
9200
- /**
9201
- * Return content to be printed before all file results.
9202
- * @return {String} to prepend before all results
9203
- */
9204
- startFormat: function() {
9205
- return "";
9206
- },
9207
-
9208
- /**
9209
- * Return content to be printed after all file results.
9210
- * @return {String} to append after all results
9211
- */
9212
- endFormat: function() {
9213
- return "";
9214
- },
9215
-
9216
- /**
9217
- * Given CSS Lint results for a file, return output for this format.
9218
- * @param results {Object} with error and warning messages
9219
- * @param filename {String} relative file path
9220
- * @param options {Object} (Optional) specifies special handling of output
9221
- * @return {String} output for results
9222
- */
9223
- formatResults: function(results, filename, options) {
9224
- var messages = results.messages,
9225
- output = "";
9226
- options = options || {};
9227
-
9228
- if (messages.length === 0) {
9229
- return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
9230
- }
9231
-
9232
- output = "\n\ncsslint: There are " + messages.length + " problems in " + filename + ".";
9233
- var pos = filename.lastIndexOf("/"),
9234
- shortFilename = filename;
9235
-
9236
- if (pos === -1){
9237
- pos = filename.lastIndexOf("\\");
9238
- }
9239
- if (pos > -1){
9240
- shortFilename = filename.substring(pos+1);
9241
- }
9242
-
9243
- CSSLint.Util.forEach(messages, function (message, i) {
9244
- output = output + "\n\n" + shortFilename;
9245
- if (message.rollup) {
9246
- output += "\n" + (i+1) + ": " + message.type;
9247
- output += "\n" + message.message;
9248
- } else {
9249
- output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
9250
- output += "\n" + message.message;
9251
- output += "\n" + message.evidence;
9252
- }
9253
- });
9254
-
9255
- return output;
9256
- }
9257
- });
9258
- return CSSLint;
9259
- })();
9260
- /*
9261
- * Encapsulates all of the CLI functionality. The api argument simply
9262
- * provides environment-specific functionality.
9263
- */
9264
- /*global CSSLint*/
9265
- function cli(api){
9266
-
9267
- var globalOptions = {
9268
- "help" : { "format" : "", "description" : "Displays this information."},
9269
- "format" : { "format" : "<format>", "description" : "Indicate which format to use for output."},
9270
- "list-rules" : { "format" : "", "description" : "Outputs all of the rules available."},
9271
- "quiet" : { "format" : "", "description" : "Only output when errors are present."},
9272
- "errors" : { "format" : "<rule[,rule]+>", "description" : "Indicate which rules to include as errors."},
9273
- "warnings" : { "format" : "<rule[,rule]+>", "description" : "Indicate which rules to include as warnings."},
9274
- "ignore" : { "format" : "<rule[,rule]+>", "description" : "Indicate which rules to ignore completely."},
9275
- "exclude-list": { "format" : "<file|dir[,file|dir]+>", "description" : "Indicate which files/directories to exclude from being linted."},
9276
- "version" : { "format" : "", "description" : "Outputs the current version number."}
9277
- };
9278
-
9279
- //-------------------------------------------------------------------------
9280
- // Helper functions
9281
- //-------------------------------------------------------------------------
9282
-
9283
- /**
9284
- * Returns an array of messages for a particular type.
9285
- * @param messages {Array} Array of CSS Lint messages.
9286
- * @param type {String} The type of message to filter on.
9287
- * @return {Array} An array of matching messages.
9288
- */
9289
- function pluckByType(messages, type){
9290
- return messages.filter(function(message) {
9291
- return message.type === type;
9292
- });
9293
- }
9294
-
9295
- /**
9296
- * Returns a ruleset object based on the CLI options.
9297
- * @param options {Object} The CLI options.
9298
- * @return {Object} A ruleset object.
9299
- */
9300
- function gatherRules(options, ruleset){
9301
- var warnings = options.rules || options.warnings,
9302
- errors = options.errors;
9303
-
9304
- if (warnings){
9305
- ruleset = ruleset || {};
9306
- warnings.split(",").forEach(function(value){
9307
- ruleset[value] = 1;
9308
- });
9309
- }
9310
-
9311
- if (errors){
9312
- ruleset = ruleset || {};
9313
- errors.split(",").forEach(function(value){
9314
- ruleset[value] = 2;
9315
- });
9316
- }
9317
-
9318
- return ruleset;
9319
- }
9320
-
9321
- /**
9322
- * Filters out rules using the ignore command line option.
9323
- * @param options {Object} the CLI options
9324
- * @return {Object} A ruleset object.
9325
- */
9326
- function filterRules(options) {
9327
- var ignore = options.ignore,
9328
- ruleset = null;
9329
-
9330
- if (ignore) {
9331
- ruleset = CSSLint.getRuleset();
9332
- ignore.split(",").forEach(function(value){
9333
- ruleset[value] = 0;
9334
- });
9335
- }
9336
-
9337
- return ruleset;
9338
- }
9339
-
9340
-
9341
- /**
9342
- * Filters out files using the exclude-list command line option.
9343
- * @param files {Array} the list of files to check for exclusions
9344
- * @param options {Object} the CLI options
9345
- * @return {Array} A list of files
9346
- */
9347
- function filterFiles(files, options) {
9348
- var excludeList = options["exclude-list"],
9349
- excludeFiles = [],
9350
- filesToLint = files.map(api.getFullPath),
9351
- fullPath;
9352
-
9353
-
9354
- if (excludeList) {
9355
- // Build up the exclude list, expanding any directory exclusions that were passed in
9356
- excludeList.split(",").forEach(function(value){
9357
- if (api.isDirectory(value)) {
9358
- excludeFiles = excludeFiles.concat(api.getFiles(value));
9359
- } else {
9360
- excludeFiles.push(value);
9361
- }
9362
- });
9363
-
9364
- // Remove the excluded files from the list of files to lint
9365
- excludeFiles.forEach(function(value){
9366
- fullPath = api.getFullPath(value);
9367
- if (filesToLint.indexOf(fullPath) > -1) {
9368
- filesToLint.splice(filesToLint.indexOf(fullPath),1);
9369
- }
9370
- });
9371
- }
9372
-
9373
- return filesToLint;
9374
- }
9375
-
9376
- /**
9377
- * Outputs all available rules to the CLI.
9378
- * @return {void}
9379
- */
9380
- function printRules(){
9381
- api.print("");
9382
- var rules = CSSLint.getRules();
9383
- rules.forEach(function(rule){
9384
- api.print(rule.id + "\n " + rule.desc + "\n");
9385
- });
9386
- }
9387
-
9388
- /**
9389
- * Given a file name and options, run verification and print formatted output.
9390
- * @param {String} relativeFilePath absolute file location
9391
- * @param {Object} options for processing
9392
- * @return {Number} exit code
9393
- */
9394
- function processFile(relativeFilePath, options) {
9395
- var input = api.readFile(relativeFilePath),
9396
- ruleset = filterRules(options),
9397
- result = CSSLint.verify(input, gatherRules(options, ruleset)),
9398
- formatter = CSSLint.getFormatter(options.format || "text"),
9399
- messages = result.messages || [],
9400
- output,
9401
- exitCode = 0;
9402
-
9403
- if (!input) {
9404
- if (formatter.readError) {
9405
- api.print(formatter.readError(relativeFilePath, "Could not read file data. Is the file empty?"));
9406
- } else {
9407
- api.print("csslint: Could not read file data in " + relativeFilePath + ". Is the file empty?");
9408
- }
9409
- exitCode = 1;
9410
- } else {
9411
- //var relativeFilePath = getRelativePath(api.getWorkingDirectory(), fullFilePath);
9412
- options.fullPath = api.getFullPath(relativeFilePath);
9413
- output = formatter.formatResults(result, relativeFilePath, options);
9414
- if (output){
9415
- api.print(output);
9416
- }
9417
-
9418
- if (messages.length > 0 && pluckByType(messages, "error").length > 0) {
9419
- exitCode = 1;
9420
- }
9421
- }
9422
-
9423
- return exitCode;
9424
- }
9425
-
9426
-
9427
- /**
9428
- * Outputs the help screen to the CLI.
9429
- * @return {void}
9430
- */
9431
- function outputHelp(){
9432
- var lenToPad = 40,
9433
- toPrint = '',
9434
- formatString = '';
9435
-
9436
- api.print([
9437
- "\nUsage: csslint-rhino.js [options]* [file|dir]*",
9438
- " ",
9439
- "Global Options"
9440
- ].join("\n"));
9441
-
9442
- for (var optionName in globalOptions) {
9443
- if (globalOptions.hasOwnProperty(optionName)) {
9444
- // Print the option name and the format if present
9445
- toPrint += " --" + optionName;
9446
- if (globalOptions[optionName].format !== "") {
9447
- formatString = '=' + globalOptions[optionName].format;
9448
- toPrint += formatString;
9449
- } else {
9450
- formatString = '';
9451
- }
9452
-
9453
- // Pad out with the appropriate number of spaces
9454
- toPrint += new Array(lenToPad - (optionName.length + formatString.length)).join(' ');
9455
-
9456
- // Print the description
9457
- toPrint += globalOptions[optionName].description + "\n";
9458
- }
9459
- }
9460
- api.print(toPrint);
9461
- }
9462
-
9463
- /**
9464
- * Given an Array of filenames, print wrapping output and process them.
9465
- * @param files {Array} filenames list
9466
- * @param options {Object} options object
9467
- * @return {Number} exit code
9468
- */
9469
- function processFiles(fileArray, options){
9470
- var exitCode = 0,
9471
- formatId = options.format || "text",
9472
- formatter,
9473
- files = filterFiles(fileArray,options),
9474
- output;
9475
-
9476
- if (!files.length) {
9477
- api.print("csslint: No files specified.");
9478
- exitCode = 1;
9479
- } else {
9480
- if (!CSSLint.hasFormat(formatId)){
9481
- api.print("csslint: Unknown format '" + formatId + "'. Cannot proceed.");
9482
- exitCode = 1;
9483
- } else {
9484
- formatter = CSSLint.getFormatter(formatId);
9485
-
9486
- output = formatter.startFormat();
9487
- if (output){
9488
- api.print(output);
9489
- }
9490
-
9491
-
9492
- files.forEach(function(file){
9493
- if (exitCode === 0) {
9494
- exitCode = processFile(file,options);
9495
- } else {
9496
- processFile(file,options);
9497
- }
9498
- });
9499
-
9500
- output = formatter.endFormat();
9501
- if (output){
9502
- api.print(output);
9503
- }
9504
- }
9505
- }
9506
- return exitCode;
9507
- }
9508
-
9509
-
9510
- function processArguments(args, options) {
9511
- var arg = args.shift(),
9512
- argName,
9513
- parts,
9514
- files = [];
9515
-
9516
- while(arg){
9517
- if (arg.indexOf("--") === 0){
9518
- argName = arg.substring(2);
9519
-
9520
- if (argName.indexOf("=") > -1){
9521
- parts = argName.split("=");
9522
- options[parts[0]] = parts[1];
9523
- } else {
9524
- options[argName] = true;
9525
- }
9526
-
9527
- } else {
9528
-
9529
- //see if it's a directory or a file
9530
- if (api.isDirectory(arg)){
9531
- files = files.concat(api.getFiles(arg));
9532
- } else {
9533
- files.push(arg);
9534
- }
9535
- }
9536
- arg = args.shift();
9537
- }
9538
-
9539
- options.files = files;
9540
- return options;
9541
- }
9542
-
9543
- function validateOptions(options) {
9544
- for (var option_key in options) {
9545
- if (!globalOptions.hasOwnProperty(option_key) && option_key !== 'files') {
9546
- api.print(option_key + ' is not a valid option. Exiting...');
9547
- outputHelp();
9548
- api.quit(0);
9549
- }
9550
- }
9551
- }
9552
-
9553
- function readConfigFile(options) {
9554
- var data = api.readFile(api.getFullPath(".csslintrc"));
9555
- if (data) {
9556
- options = processArguments(data.split(/[\s\n\r]+/m), options);
9557
- }
9558
-
9559
- return options;
9560
- }
9561
-
9562
-
9563
-
9564
- //-----------------------------------------------------------------------------
9565
- // Process command line
9566
- //-----------------------------------------------------------------------------
9567
-
9568
- var args = api.args,
9569
- argCount = args.length,
9570
- options = {};
9571
-
9572
- // first look for config file .csslintrc
9573
- options = readConfigFile(options);
9574
-
9575
- // Command line arguments override config file
9576
- options = processArguments(args, options);
9577
-
9578
- if (options.help || argCount === 0){
9579
- outputHelp();
9580
- api.quit(0);
9581
- }
9582
-
9583
- // Validate options
9584
- validateOptions(options);
9585
-
9586
- if (options.version){
9587
- api.print("v" + CSSLint.version);
9588
- api.quit(0);
9589
- }
9590
-
9591
- if (options["list-rules"]){
9592
- printRules();
9593
- api.quit(0);
9594
- }
9595
-
9596
- api.quit(processFiles(options.files,options));
9597
- }
9598
-
9599
- /*
9600
- * CSSLint Rhino Command Line Interface
9601
- */
9602
- /*jshint rhino:true*/
9603
- /*global cli, File*/
9604
-
9605
- importPackage(java.io);
9606
-
9607
- cli({
9608
- args: Array.prototype.concat.call(arguments),
9609
- print: print,
9610
- quit: quit,
9611
-
9612
- isDirectory: function(name){
9613
- var dir = new File(name);
9614
- return dir.isDirectory();
9615
- },
9616
-
9617
- getFiles: function(dir){
9618
- var files = [];
9619
-
9620
- function traverse(dir) {
9621
- var dirList = dir.listFiles();
9622
- dirList.forEach(function (file) {
9623
- if (/\.css$/.test(file)) {
9624
- files.push(file.toString());
9625
- } else if (file.isDirectory()) {
9626
- traverse(file);
9627
- }
9628
- });
9629
- }
9630
-
9631
- traverse(new File(dir));
9632
-
9633
- return files;
9634
- },
9635
-
9636
- getWorkingDirectory: function() {
9637
- return (new File(".")).getCanonicalPath();
9638
- },
9639
-
9640
- getFullPath: function(filename){
9641
- return (new File(filename)).getCanonicalPath();
9642
- },
9643
-
9644
- readFile: function(filename) {
9645
- try {
9646
- return readFile(filename);
9647
- } catch (ex) {
9648
- return "";
9649
- }
9650
- }
9651
- });