Skip to content

Commit 93c4ac2

Browse files
author
Nicholas C. Zakas
committed
Updated parser to deal with CSS escaping (fixes CSSLint#97)
1 parent 82ea477 commit 93c4ac2

File tree

9 files changed

+328
-69
lines changed

9 files changed

+328
-69
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Next (not yet released)
22

3+
* Updated parser to handle CSS escaping (fixes #97)
34
* Added a rule to check for high text-indent for RTL (fixes #109)
45
* Add rule to warn for universal selector (fixes #38)
56
* Changed too many !important error to warning (fixes #105)

build/csslint-node.js

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
THE SOFTWARE.
2222
2323
*/
24-
/* Build time: 12-July-2011 03:27:00 */
24+
/* Build time: 13-July-2011 04:31:39 */
2525
/*!
2626
Parser-Lib
2727
Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.
@@ -45,7 +45,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4545
THE SOFTWARE.
4646
4747
*/
48-
/* Build time: 11-July-2011 04:28:24 */
48+
/* Build time: 12-July-2011 11:25:19 */
4949
var parserlib = {};
5050
(function(){
5151

@@ -941,7 +941,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
941941
THE SOFTWARE.
942942
943943
*/
944-
/* Build time: 11-July-2011 04:28:24 */
944+
/* Build time: 12-July-2011 11:25:19 */
945945
(function(){
946946
var EventTarget = parserlib.util.EventTarget,
947947
TokenStreamBase = parserlib.util.TokenStreamBase,
@@ -3802,11 +3802,11 @@ function isNameStart(c){
38023802
}
38033803

38043804
function isNameChar(c){
3805-
return c != null && (isNameStart(c) || /[0-9\-]/.test(c));
3805+
return c != null && (isNameStart(c) || /[0-9\-\\]/.test(c));
38063806
}
38073807

38083808
function isIdentStart(c){
3809-
return c != null && (isNameStart(c) || c == "-");
3809+
return c != null && (isNameStart(c) || /\-\\/.test(c));
38103810
}
38113811

38123812
function mix(receiver, supplier){
@@ -4705,14 +4705,44 @@ TokenStream.prototype = mix(new TokenStreamBase(), {
47054705
ident = first || "",
47064706
c = reader.peek();
47074707

4708-
4709-
while(c && isNameChar(c)){
4710-
ident += reader.read();
4711-
c = reader.peek();
4708+
while(true){
4709+
if (c == "\\"){
4710+
ident += this.readEscape(reader.read());
4711+
c = reader.peek();
4712+
} else if(c && isNameChar(c)){
4713+
ident += reader.read();
4714+
c = reader.peek();
4715+
} else {
4716+
break;
4717+
}
47124718
}
47134719

47144720
return ident;
47154721
},
4722+
4723+
readEscape: function(first){
4724+
var reader = this._reader,
4725+
cssEscape = first || "",
4726+
i = 0,
4727+
c = reader.peek();
4728+
4729+
if (isHexDigit(c)){
4730+
do {
4731+
cssEscape += reader.read();
4732+
c = reader.peek();
4733+
} while(c && isHexDigit(c) && ++i < 6);
4734+
}
4735+
4736+
if (cssEscape.length == 3 && /\s/.test(c) ||
4737+
cssEscape.length == 7 || cssEscape.length == 1){
4738+
reader.read();
4739+
} else {
4740+
c = "";
4741+
}
4742+
4743+
return cssEscape + c;
4744+
},
4745+
47164746
readComment: function(first){
47174747
var reader = this._reader,
47184748
comment = first || "",
@@ -4962,6 +4992,7 @@ TokenStream :TokenStream,
49624992
Tokens :Tokens
49634993
};
49644994
})();
4995+
49654996
/**
49664997
* YUI Test Framework
49674998
* @module yuitest
@@ -9523,6 +9554,7 @@ YUITest.PageManager = YUITest.Util.mix(new YUITest.EventTarget(), {
95239554
return new TestRunner();
95249555

95259556
}();
9557+
95269558
/**
95279559
* Main CSSLint object.
95289560
* @class CSSLint
@@ -9673,6 +9705,7 @@ var CSSLint = (function(){
96739705
return api;
96749706

96759707
})();
9708+
96769709
/**
96779710
* An instance of Report is used to report results of the
96789711
* verification back to the main API.
@@ -9807,6 +9840,7 @@ Reporter.prototype = {
98079840
this.stats[name] = value;
98089841
}
98099842
};
9843+
98109844
/*
98119845
* Utility functions that make life easier.
98129846
*/
@@ -10780,7 +10814,7 @@ CSSLint.addRule({
1078010814
* Should we be checking for rtl/ltr?
1078110815
*/
1078210816
//Commented out due to lack of tests
10783-
/*CSSLint.addRule({
10817+
CSSLint.addRule({
1078410818

1078510819
//rule information
1078610820
id: "text-indent",
@@ -10795,15 +10829,15 @@ CSSLint.addRule({
1079510829
//check for use of "font-size"
1079610830
parser.addListener("property", function(event){
1079710831
var name = event.property,
10798-
value = event.value;
10832+
value = event.value.parts[0].value;
1079910833

1080010834
if (name == "text-indent" && value < -99){
1080110835
reporter.warn("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set text-direction for that item to ltr.", name.line, name.col, rule);
1080210836
}
1080310837
});
1080410838
}
1080510839

10806-
});*/
10840+
});
1080710841
/*
1080810842
* Rule: Headings (h1-h6) should be defined only once.
1080910843
*/

build/csslint-rhino.js

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
THE SOFTWARE.
2222
2323
*/
24-
/* Build time: 12-July-2011 03:27:00 */
24+
/* Build time: 13-July-2011 04:31:39 */
2525
var CSSLint = (function(){
2626
/*!
2727
Parser-Lib
@@ -46,7 +46,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4646
THE SOFTWARE.
4747
4848
*/
49-
/* Build time: 11-July-2011 04:28:24 */
49+
/* Build time: 12-July-2011 11:25:19 */
5050
var parserlib = {};
5151
(function(){
5252

@@ -942,7 +942,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
942942
THE SOFTWARE.
943943
944944
*/
945-
/* Build time: 11-July-2011 04:28:24 */
945+
/* Build time: 12-July-2011 11:25:19 */
946946
(function(){
947947
var EventTarget = parserlib.util.EventTarget,
948948
TokenStreamBase = parserlib.util.TokenStreamBase,
@@ -3803,11 +3803,11 @@ function isNameStart(c){
38033803
}
38043804

38053805
function isNameChar(c){
3806-
return c != null && (isNameStart(c) || /[0-9\-]/.test(c));
3806+
return c != null && (isNameStart(c) || /[0-9\-\\]/.test(c));
38073807
}
38083808

38093809
function isIdentStart(c){
3810-
return c != null && (isNameStart(c) || c == "-");
3810+
return c != null && (isNameStart(c) || /\-\\/.test(c));
38113811
}
38123812

38133813
function mix(receiver, supplier){
@@ -4706,14 +4706,44 @@ TokenStream.prototype = mix(new TokenStreamBase(), {
47064706
ident = first || "",
47074707
c = reader.peek();
47084708

4709-
4710-
while(c && isNameChar(c)){
4711-
ident += reader.read();
4712-
c = reader.peek();
4709+
while(true){
4710+
if (c == "\\"){
4711+
ident += this.readEscape(reader.read());
4712+
c = reader.peek();
4713+
} else if(c && isNameChar(c)){
4714+
ident += reader.read();
4715+
c = reader.peek();
4716+
} else {
4717+
break;
4718+
}
47134719
}
47144720

47154721
return ident;
47164722
},
4723+
4724+
readEscape: function(first){
4725+
var reader = this._reader,
4726+
cssEscape = first || "",
4727+
i = 0,
4728+
c = reader.peek();
4729+
4730+
if (isHexDigit(c)){
4731+
do {
4732+
cssEscape += reader.read();
4733+
c = reader.peek();
4734+
} while(c && isHexDigit(c) && ++i < 6);
4735+
}
4736+
4737+
if (cssEscape.length == 3 && /\s/.test(c) ||
4738+
cssEscape.length == 7 || cssEscape.length == 1){
4739+
reader.read();
4740+
} else {
4741+
c = "";
4742+
}
4743+
4744+
return cssEscape + c;
4745+
},
4746+
47174747
readComment: function(first){
47184748
var reader = this._reader,
47194749
comment = first || "",
@@ -4963,6 +4993,7 @@ TokenStream :TokenStream,
49634993
Tokens :Tokens
49644994
};
49654995
})();
4996+
49664997
/**
49674998
* YUI Test Framework
49684999
* @module yuitest
@@ -9524,6 +9555,7 @@ YUITest.PageManager = YUITest.Util.mix(new YUITest.EventTarget(), {
95249555
return new TestRunner();
95259556

95269557
}();
9558+
95279559
/**
95289560
* Main CSSLint object.
95299561
* @class CSSLint
@@ -9674,6 +9706,7 @@ var CSSLint = (function(){
96749706
return api;
96759707

96769708
})();
9709+
96779710
/**
96789711
* An instance of Report is used to report results of the
96799712
* verification back to the main API.
@@ -9808,6 +9841,7 @@ Reporter.prototype = {
98089841
this.stats[name] = value;
98099842
}
98109843
};
9844+
98119845
/*
98129846
* Utility functions that make life easier.
98139847
*/
@@ -10781,7 +10815,7 @@ CSSLint.addRule({
1078110815
* Should we be checking for rtl/ltr?
1078210816
*/
1078310817
//Commented out due to lack of tests
10784-
/*CSSLint.addRule({
10818+
CSSLint.addRule({
1078510819

1078610820
//rule information
1078710821
id: "text-indent",
@@ -10796,15 +10830,15 @@ CSSLint.addRule({
1079610830
//check for use of "font-size"
1079710831
parser.addListener("property", function(event){
1079810832
var name = event.property,
10799-
value = event.value;
10833+
value = event.value.parts[0].value;
1080010834

1080110835
if (name == "text-indent" && value < -99){
1080210836
reporter.warn("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set text-direction for that item to ltr.", name.line, name.col, rule);
1080310837
}
1080410838
});
1080510839
}
1080610840

10807-
});*/
10841+
});
1080810842
/*
1080910843
* Rule: Headings (h1-h6) should be defined only once.
1081010844
*/
@@ -11166,6 +11200,7 @@ CSSLint.addFormatter({
1116611200

1116711201
return CSSLint;
1116811202
})();
11203+
1116911204
//print for rhino and nodejs
1117011205
if(typeof print == "undefined") {
1117111206
var print = console.log;
@@ -11331,3 +11366,4 @@ if (options.version){
1133111366

1133211367

1133311368
quit(processFiles(files,options));
11369+

0 commit comments

Comments
 (0)