Skip to content

Commit 8e1a35d

Browse files
author
Nicholas C. Zakas
committed
Updated parser (fixes #206 and fixes #209)
1 parent f38f26b commit 8e1a35d

File tree

2 files changed

+85
-45
lines changed

2 files changed

+85
-45
lines changed

demos/demo.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@namespace svg "http://www.w3.org/2000/svg";
99

1010
li.inline #foo {
11-
background: url("something.png");
11+
background: rgba(234, 212, 200, 0.5) url("something.png");
1212
display: inline;
1313
padding-left: 3px;
1414
padding-right: 7px;
@@ -40,4 +40,4 @@ li.last.first {
4040
font-size: 2em;
4141
content: counter(page);
4242
}
43-
}
43+
}

lib/parserlib.js

Lines changed: 83 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
THE SOFTWARE.
2222
2323
*/
24-
/* Build time: 25-October-2011 09:11:57 */
24+
/* Build time: 1-November-2011 12:11:55 */
2525
var parserlib = {};
2626
(function(){
2727

28-
2928
/**
3029
* A generic base to inherit from for any object
3130
* that needs event handling.
@@ -895,8 +894,6 @@ TokenStreamBase.prototype = {
895894
};
896895

897896

898-
899-
900897
parserlib.util = {
901898
StringReader: StringReader,
902899
SyntaxError : SyntaxError,
@@ -905,8 +902,6 @@ EventTarget : EventTarget,
905902
TokenStreamBase : TokenStreamBase
906903
};
907904
})();
908-
909-
910905
/*
911906
Parser-Lib
912907
Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.
@@ -930,15 +925,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
930925
THE SOFTWARE.
931926
932927
*/
933-
/* Build time: 25-October-2011 09:11:57 */
928+
/* Build time: 1-November-2011 12:11:55 */
934929
(function(){
935930
var EventTarget = parserlib.util.EventTarget,
936931
TokenStreamBase = parserlib.util.TokenStreamBase,
937932
StringReader = parserlib.util.StringReader,
938933
SyntaxError = parserlib.util.SyntaxError,
939934
SyntaxUnit = parserlib.util.SyntaxUnit;
940935

941-
942936
var Colors = {
943937
aliceblue :"#f0f8ff",
944938
antiquewhite :"#faebd7",
@@ -1118,7 +1112,6 @@ function Combinator(text, line, col){
11181112
Combinator.prototype = new SyntaxUnit();
11191113
Combinator.prototype.constructor = Combinator;
11201114

1121-
11221115
/**
11231116
* Represents a media feature, such as max-width:500.
11241117
* @namespace parserlib.css
@@ -1150,7 +1143,6 @@ function MediaFeature(name, value){
11501143
MediaFeature.prototype = new SyntaxUnit();
11511144
MediaFeature.prototype.constructor = MediaFeature;
11521145

1153-
11541146
/**
11551147
* Represents an individual media query.
11561148
* @namespace parserlib.css
@@ -1193,7 +1185,6 @@ function MediaQuery(modifier, mediaType, features, line, col){
11931185
MediaQuery.prototype = new SyntaxUnit();
11941186
MediaQuery.prototype.constructor = MediaQuery;
11951187

1196-
11971188
/**
11981189
* A CSS3 parser.
11991190
* @namespace parserlib.css
@@ -3371,12 +3362,22 @@ nth
33713362
['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*
33723363
;
33733364
*/
3365+
//This file will likely change a lot! Very experimental!
3366+
33743367
var ValidationType = {
33753368

33763369
"absolute-size": function(part){
33773370
return this.identifier(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
33783371
},
33793372

3373+
"attachment": function(part){
3374+
return this.identifier(part, "scroll | fixed | local");
3375+
},
3376+
3377+
"box": function(part){
3378+
return this.identifier(part, "padding-box | border-box | content-box");
3379+
},
3380+
33803381
"relative-size": function(part){
33813382
return this.identifier(part, "smaller | larger");
33823383
},
@@ -3424,6 +3425,10 @@ var ValidationType = {
34243425
return this.uri(part);
34253426
},
34263427

3428+
"bg-image": function(part){
3429+
return this.image(part) || part == "none";
3430+
},
3431+
34273432
"percentage": function(part){
34283433
return part.type == "percentage" || part == "0";
34293434
},
@@ -3458,25 +3463,25 @@ var Properties = {
34583463
"alignment-baseline": 1,
34593464
"animation": 1,
34603465
"animation-delay": 1,
3461-
"animation-direction": 1,
3466+
"animation-direction": { multi: [ "normal | alternate" ], separator: "," },
34623467
"animation-duration": 1,
34633468
"animation-fill-mode": 1,
3464-
"animation-iteration-count": 1,
3469+
"animation-iteration-count": { multi: [ "number", "infinite"], separator: "," },
34653470
"animation-name": 1,
3466-
"animation-play-state": 1,
3471+
"animation-play-state": { multi: [ "running | paused" ], separator: "," },
34673472
"animation-timing-function": 1,
34683473
"appearance": 1,
34693474
"azimuth": 1,
34703475

34713476
//B
34723477
"backface-visibility": 1,
34733478
"background": 1,
3474-
"background-attachment": [ "scroll | fixed | inherit" ],
3479+
"background-attachment": { multi: [ "attachment" ], separator: "," },
34753480
"background-break": 1,
3476-
"background-clip": 1,
3481+
"background-clip": { multi: [ "box" ], separator: "," },
34773482
"background-color": [ "color", "inherit" ],
3478-
"background-image": 1,
3479-
"background-origin": 1,
3483+
"background-image": { multi: [ "bg-image" ], separator: "," },
3484+
"background-origin": { multi: [ "box" ], separator: "," },
34803485
"background-position": 1,
34813486
"background-repeat": [ "repeat | repeat-x | repeat-y | no-repeat | inherit" ],
34823487
"background-size": 1,
@@ -3634,7 +3639,7 @@ var Properties = {
36343639
"line-stacking-strategy": 1,
36353640
"list-style": 1,
36363641
"list-style-image": [ "uri", "none | inherit" ],
3637-
"list-style-position": [ "inside | outsider | inherit" ],
3642+
"list-style-position": [ "inside | outside | inherit" ],
36383643
"list-style-type": [ "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit" ],
36393644

36403645
//M
@@ -3744,6 +3749,7 @@ var Properties = {
37443749
"text-indent": [ "length", "percentage", "inherit" ],
37453750
"text-justify": [ "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida" ],
37463751
"text-outline": 1,
3752+
"text-overflow": 1,
37473753
"text-shadow": 1,
37483754
"text-transform": [ "capitalize | uppercase | lowercase | none | inherit" ],
37493755
"text-wrap": [ "normal | none | avoid" ],
@@ -3827,8 +3833,10 @@ var Properties = {
38273833
i, len, j, count,
38283834
msg,
38293835
values,
3836+
last,
38303837
parts = value.parts;
38313838

3839+
//if there's a maximum set, use it (max can't be 0)
38323840
if (spec.max) {
38333841
if (parts.length > spec.max){
38343842
throw new ValidationError("Expected a max of " + spec.max + " property values but found " + parts.length + ".", value.line, value.col);
@@ -3842,25 +3850,45 @@ var Properties = {
38423850
for (i=0, len=parts.length; i < len; i++){
38433851
msg = [];
38443852
valid = false;
3845-
for (j=0, count=values.length; j < count; j++){
3846-
if (typeof ValidationType[values[j]] == "undefined"){
3847-
if(ValidationType.identifier(parts[i], values[j])){
3848-
valid = true;
3849-
break;
3850-
}
3851-
msg.push("one of (" + values[j] + ")");
3853+
3854+
if (spec.separator && parts[i].type == "operator"){
3855+
3856+
//two operators in a row - not allowed?
3857+
if ((last && last.type == "operator")){
3858+
msg = msg.concat(values);
3859+
} else if (i == len-1){
3860+
msg = msg.concat("end of line");
3861+
} else if (parts[i] != spec.separator){
3862+
msg.push("'" + spec.separator + "'");
38523863
} else {
3853-
if (ValidationType[values[j]](parts[i])){
3854-
valid = true;
3855-
break;
3856-
}
3857-
msg.push(values[j]);
3858-
}
3864+
valid = true;
3865+
}
3866+
} else {
3867+
3868+
for (j=0, count=values.length; j < count; j++){
3869+
if (typeof ValidationType[values[j]] == "undefined"){
3870+
if(ValidationType.identifier(parts[i], values[j])){
3871+
valid = true;
3872+
break;
3873+
}
3874+
msg.push("one of (" + values[j] + ")");
3875+
} else {
3876+
if (ValidationType[values[j]](parts[i])){
3877+
valid = true;
3878+
break;
3879+
}
3880+
msg.push(values[j]);
3881+
}
3882+
}
38593883
}
3884+
38603885

38613886
if (!valid) {
38623887
throw new ValidationError("Expected " + msg.join(" or ") + " but found '" + parts[i] + "'.", value.line, value.col);
38633888
}
3889+
3890+
3891+
last = parts[i];
38643892
}
38653893

38663894
};
@@ -3898,7 +3926,6 @@ PropertyName.prototype.constructor = PropertyName;
38983926
PropertyName.prototype.toString = function(){
38993927
return (this.hack ? this.hack : "") + this.text;
39003928
};
3901-
39023929
/**
39033930
* Represents a single part of a CSS property value, meaning that it represents
39043931
* just everything single part between ":" and ";". If there are multiple values
@@ -3927,7 +3954,6 @@ function PropertyValue(parts, line, col){
39273954
PropertyValue.prototype = new SyntaxUnit();
39283955
PropertyValue.prototype.constructor = PropertyValue;
39293956

3930-
39313957
/**
39323958
* Represents a single part of a CSS property value, meaning that it represents
39333959
* just one part of the data between ":" and ";".
@@ -4035,6 +4061,29 @@ function PropertyValuePart(text, line, col){
40354061
this.red = +RegExp.$1 * 255 / 100;
40364062
this.green = +RegExp.$2 * 255 / 100;
40374063
this.blue = +RegExp.$3 * 255 / 100;
4064+
} else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
4065+
this.type = "color";
4066+
this.red = +RegExp.$1;
4067+
this.green = +RegExp.$2;
4068+
this.blue = +RegExp.$3;
4069+
this.alpha = +RegExp.$4;
4070+
} else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
4071+
this.type = "color";
4072+
this.red = +RegExp.$1 * 255 / 100;
4073+
this.green = +RegExp.$2 * 255 / 100;
4074+
this.blue = +RegExp.$3 * 255 / 100;
4075+
this.alpha = +RegExp.$4;
4076+
} else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
4077+
this.type = "color";
4078+
this.hue = +RegExp.$1;
4079+
this.saturation = +RegExp.$2 / 100;
4080+
this.lightness = +RegExp.$3 / 100;
4081+
} else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
4082+
this.type = "color";
4083+
this.hue = +RegExp.$1;
4084+
this.saturation = +RegExp.$2 / 100;
4085+
this.lightness = +RegExp.$3 / 100;
4086+
this.alpha = +RegExp.$4;
40384087
} else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
40394088
this.type = "uri";
40404089
this.uri = RegExp.$1;
@@ -4119,7 +4168,6 @@ function Selector(parts, line, col){
41194168
Selector.prototype = new SyntaxUnit();
41204169
Selector.prototype.constructor = Selector;
41214170

4122-
41234171
/**
41244172
* Represents a single part of a selector string, meaning a single set of
41254173
* element name and modifiers. This does not include combinators such as
@@ -4161,7 +4209,6 @@ function SelectorPart(elementName, modifiers, text, line, col){
41614209
SelectorPart.prototype = new SyntaxUnit();
41624210
SelectorPart.prototype.constructor = SelectorPart;
41634211

4164-
41654212
/**
41664213
* Represents a selector modifier string, meaning a class name, element name,
41674214
* element ID, pseudo rule, etc.
@@ -4197,7 +4244,6 @@ function SelectorSubPart(text, type, line, col){
41974244
SelectorSubPart.prototype = new SyntaxUnit();
41984245
SelectorSubPart.prototype.constructor = SelectorSubPart;
41994246

4200-
42014247
/**
42024248
* Represents a selector's specificity.
42034249
* @namespace parserlib.css
@@ -4320,7 +4366,6 @@ Specificity.calculate = function(selector){
43204366
};
43214367

43224368

4323-
43244369
var h = /^[0-9a-fA-F]$/,
43254370
nonascii = /^[\u0080-\uFFFF]$/,
43264371
nl = /\n|\r\n|\r|\f/;
@@ -5318,7 +5363,6 @@ TokenStream.prototype = mix(new TokenStreamBase(), {
53185363
}
53195364
});
53205365

5321-
53225366
var Tokens = [
53235367

53245368
/*
@@ -5525,7 +5569,6 @@ var Tokens = [
55255569

55265570

55275571

5528-
55295572
/**
55305573
* Type to use when a validation error occurs.
55315574
* @class ValidationError
@@ -5563,7 +5606,6 @@ function ValidationError(message, line, col){
55635606
//inherit from Error
55645607
ValidationError.prototype = new Error();
55655608

5566-
55675609
parserlib.css = {
55685610
Colors :Colors,
55695611
Combinator :Combinator,
@@ -5582,5 +5624,3 @@ Tokens :Tokens,
55825624
ValidationError :ValidationError
55835625
};
55845626
})();
5585-
5586-

0 commit comments

Comments
 (0)