Skip to content

Commit c7fef82

Browse files
committed
Simplify ValidationTypes using Matcher framework.
As a side-effect, we also pushed handling the `inherit` option out of most ValidationTypes and moved it into the specification in the Properties table. I expect to refactor this further in the future to make handling of inherit/initial/unset automatic and implicit.
1 parent 4fbdfee commit c7fef82

File tree

3 files changed

+92
-290
lines changed

3 files changed

+92
-290
lines changed

src/css/Properties.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ var Properties = {
9090
"background-color" : "<color> | inherit",
9191
"background-image" : { multi: "<bg-image>", comma: true },
9292
"background-origin" : { multi: "<box>", comma: true },
93-
"background-position" : { multi: "<bg-position>", comma: true },
93+
"background-position" : "<bg-position> | inherit",
9494
"background-repeat" : { multi: "<repeat-style>", comma: true },
9595
"background-size" : { multi: "<bg-size>", comma: true },
9696
"baseline-shift" : "baseline | sub | super | <percentage> | <length>",
@@ -104,8 +104,8 @@ var Properties = {
104104
"border" : "<border-width> || <border-style> || <color>",
105105
"border-bottom" : "<border-width> || <border-style> || <color>",
106106
"border-bottom-color" : "<color> | inherit",
107-
"border-bottom-left-radius" : "<x-one-radius>",
108-
"border-bottom-right-radius" : "<x-one-radius>",
107+
"border-bottom-left-radius" : "<x-one-radius> | inherit",
108+
"border-bottom-right-radius" : "<x-one-radius> | inherit",
109109
"border-bottom-style" : "<border-style>",
110110
"border-bottom-width" : "<border-width>",
111111
"border-collapse" : "collapse | separate | inherit",
@@ -198,8 +198,8 @@ var Properties = {
198198
"border-style" : { multi: "<border-style>", max: 4 },
199199
"border-top" : "<border-width> || <border-style> || <color>",
200200
"border-top-color" : "<color> | inherit",
201-
"border-top-left-radius" : "<x-one-radius>",
202-
"border-top-right-radius" : "<x-one-radius>",
201+
"border-top-left-radius" : "<x-one-radius> | inherit",
202+
"border-top-right-radius" : "<x-one-radius> | inherit",
203203
"border-top-style" : "<border-style>",
204204
"border-top-width" : "<border-width>",
205205
"border-width" : { multi: "<border-width>", max: 4 },
@@ -420,7 +420,7 @@ var Properties = {
420420

421421
//O
422422
"object-fit" : "fill | contain | cover | none | scale-down",
423-
"object-position" : "<bg-position>",
423+
"object-position" : "<position> | inherit",
424424
"opacity" : "<number> | inherit",
425425
"order" : "<integer>",
426426
"-webkit-order" : "<integer>",

src/css/ValidationTypes.js

Lines changed: 70 additions & 270 deletions
Original file line numberDiff line numberDiff line change
@@ -509,275 +509,75 @@ ValidationTypes = {
509509

510510
complex: {
511511

512-
"<bg-position>": function(expression){
513-
var result = false,
514-
numeric = "<percentage> | <length>",
515-
xDir = "left | right",
516-
yDir = "top | bottom",
517-
count = 0;
518-
519-
while (expression.peek(count) && expression.peek(count).text !== ",") {
520-
count++;
521-
}
522-
523-
/*
524-
<position> = [
525-
[ left | center | right | top | bottom | <percentage> | <length> ]
526-
|
527-
[ left | center | right | <percentage> | <length> ]
528-
[ top | center | bottom | <percentage> | <length> ]
529-
|
530-
[ center | [ left | right ] [ <percentage> | <length> ]? ] &&
531-
[ center | [ top | bottom ] [ <percentage> | <length> ]? ]
532-
]
533-
*/
534-
535-
if (count < 3) {
536-
if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) {
537-
result = true;
538-
ValidationTypes.isAny(expression, yDir + " | center | " + numeric);
539-
} else if (ValidationTypes.isAny(expression, yDir)) {
540-
result = true;
541-
ValidationTypes.isAny(expression, xDir + " | center");
542-
}
543-
} else {
544-
if (ValidationTypes.isAny(expression, xDir)) {
545-
if (ValidationTypes.isAny(expression, yDir)) {
546-
result = true;
547-
ValidationTypes.isAny(expression, numeric);
548-
} else if (ValidationTypes.isAny(expression, numeric)) {
549-
if (ValidationTypes.isAny(expression, yDir)) {
550-
result = true;
551-
ValidationTypes.isAny(expression, numeric);
552-
} else if (ValidationTypes.isAny(expression, "center")) {
553-
result = true;
554-
}
555-
}
556-
} else if (ValidationTypes.isAny(expression, yDir)) {
557-
if (ValidationTypes.isAny(expression, xDir)) {
558-
result = true;
559-
ValidationTypes.isAny(expression, numeric);
560-
} else if (ValidationTypes.isAny(expression, numeric)) {
561-
if (ValidationTypes.isAny(expression, xDir)) {
562-
result = true;
563-
ValidationTypes.isAny(expression, numeric);
564-
} else if (ValidationTypes.isAny(expression, "center")) {
565-
result = true;
566-
}
567-
}
568-
} else if (ValidationTypes.isAny(expression, "center")) {
569-
if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) {
570-
result = true;
571-
ValidationTypes.isAny(expression, numeric);
572-
}
573-
}
574-
}
575-
576-
return result;
577-
},
578-
579-
"<bg-size>": function(expression){
580-
//<bg-size> = [ <length> | <percentage> | auto ]{1,2} | cover | contain
581-
var result = false,
582-
numeric = "<percentage> | <length> | auto";
583-
584-
if (ValidationTypes.isAny(expression, "cover | contain")) {
585-
result = true;
586-
} else if (ValidationTypes.isAny(expression, numeric)) {
587-
result = true;
588-
ValidationTypes.isAny(expression, numeric);
589-
}
590-
591-
return result;
592-
},
593-
594-
"<clip-source>": function(expression){
595-
return ValidationTypes.isAny(expression, "<uri>");
596-
},
597-
598-
"<clip-path>": function(expression) {
599-
// <basic-shape> || <geometry-box>
600-
var result = false;
601-
602-
if (ValidationTypes.isType(expression, "<basic-shape>")) {
603-
result = true;
604-
if (expression.hasNext()) {
605-
result = ValidationTypes.isType(expression, "<geometry-box>");
606-
}
607-
} else if (ValidationTypes.isType(expression, "<geometry-box>")) {
608-
result = true;
609-
if (expression.hasNext()) {
610-
result = ValidationTypes.isType(expression, "<basic-shape>");
611-
}
612-
}
613-
614-
return result && !expression.hasNext();
615-
616-
},
617-
618-
"<filter-function-list>": function(expression){
619-
var result, part, i;
620-
for (i = 0, result = true; result && expression.hasNext(); i++) {
621-
result = ValidationTypes.isAny(expression, "<filter-function> | <uri>");
622-
}
623-
624-
if (i > 1 && !result) {
625-
// More precise error message if we fail after the first
626-
// parsed <filter-function>.
627-
part = expression.peek();
628-
throw new ValidationError("Expected (<filter-function> | <uri>) but found '" + part.text + "'.", part.line, part.col);
629-
}
630-
631-
return result;
632-
633-
},
634-
635-
"<repeat-style>": function(expression){
636-
//repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2}
637-
var result = false,
638-
values = "repeat | space | round | no-repeat",
639-
part;
640-
641-
if (expression.hasNext()){
642-
part = expression.next();
643-
644-
if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
645-
result = true;
646-
} else if (ValidationTypes.isLiteral(part, values)) {
647-
result = true;
648-
649-
if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
650-
expression.next();
651-
}
652-
}
653-
}
654-
655-
return result;
656-
657-
},
658-
659-
"<shadow>": function(expression) {
660-
//inset? && [ <length>{2,4} && <color>? ]
661-
var result = false,
662-
count = 0,
663-
inset = false,
664-
color = false;
665-
666-
if (expression.hasNext()) {
667-
668-
if (ValidationTypes.isAny(expression, "inset")){
669-
inset = true;
670-
}
671-
672-
if (ValidationTypes.isAny(expression, "<color>")) {
673-
color = true;
674-
}
675-
676-
while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
677-
count++;
678-
}
679-
680-
681-
if (expression.hasNext()) {
682-
if (!color) {
683-
ValidationTypes.isAny(expression, "<color>");
684-
}
685-
686-
if (!inset) {
687-
ValidationTypes.isAny(expression, "inset");
688-
}
689-
690-
}
691-
692-
result = (count >= 2 && count <= 4);
693-
694-
}
695-
696-
return result;
697-
},
698-
699-
"<x-one-radius>": function(expression) {
700-
//[ <length> | <percentage> ] [ <length> | <percentage> ]?
701-
var result = false,
702-
simple = "<length> | <percentage> | inherit";
703-
704-
if (ValidationTypes.isAny(expression, simple)){
705-
result = true;
706-
ValidationTypes.isAny(expression, simple);
707-
}
708-
709-
return result;
710-
},
711-
712-
"<flex>": function(expression) {
713-
// http://www.w3.org/TR/2014/WD-css-flexbox-1-20140325/#flex-property
714-
// none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]
715-
// Valid syntaxes, according to https://developer.mozilla.org/en-US/docs/Web/CSS/flex#Syntax
716-
// * none
717-
// * <flex-grow>
718-
// * <flex-basis>
719-
// * <flex-grow> <flex-basis>
720-
// * <flex-grow> <flex-shrink>
721-
// * <flex-grow> <flex-shrink> <flex-basis>
722-
// * inherit
723-
var part,
724-
result = false;
725-
if (ValidationTypes.isAny(expression, "none | inherit")) {
726-
result = true;
727-
} else {
728-
if (ValidationTypes.isType(expression, "<flex-grow>")) {
729-
if (expression.peek()) {
730-
if (ValidationTypes.isType(expression, "<flex-shrink>")) {
731-
if (expression.peek()) {
732-
result = ValidationTypes.isType(expression, "<flex-basis>");
733-
} else {
734-
result = true;
735-
}
736-
} else if (ValidationTypes.isType(expression, "<flex-basis>")) {
737-
result = expression.peek() === null;
738-
}
739-
} else {
740-
result = true;
741-
}
742-
} else if (ValidationTypes.isType(expression, "<flex-basis>")) {
743-
result = true;
744-
}
745-
}
746-
747-
if (!result) {
748-
// Generate a more verbose error than "Expected <flex>..."
749-
part = expression.peek();
750-
throw new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression.value.text + "'.", part.line, part.col);
751-
}
752-
753-
return result;
754-
},
755-
756-
"<text-decoration>": function(expression) {
757-
// none | [ underline || overline || line-through || blink ] | inherit
758-
var part,
759-
result,
760-
someOf = "[ underline || overline || line-through || blink ]",
761-
identifiers = {},
762-
found;
763-
764-
do {
765-
part = expression.next();
766-
found = 0;
767-
if (someOf.indexOf(part) > -1) {
768-
if (!identifiers[part]) {
769-
identifiers[part] = 0;
770-
}
771-
identifiers[part]++;
772-
found = identifiers[part];
773-
}
774-
} while (found === 1 && expression.hasNext());
775-
776-
result = found === 1 && !expression.hasNext();
777-
if (found === 0 && JSON.stringify(identifiers) === '{}') {
778-
expression.previous();
779-
}
780-
return result;
781-
}
512+
"<bg-position>": Matcher.cast("<position>").hash(),
513+
514+
"<bg-size>":
515+
//<bg-size> = [ <length> | <percentage> | auto ]{1,2} | cover | contain
516+
Matcher.alt("cover", "contain", Matcher.cast("<percentage> | <length> | auto").braces(1,2)),
517+
518+
"<clip-source>": Matcher.cast("<uri>"),
519+
520+
"<clip-path>":
521+
// <basic-shape> || <geometry-box>
522+
Matcher.cast("<basic-shape>").oror("<geometry-box>"),
523+
524+
"<filter-function-list>":
525+
// [ <filter-function> | <uri> ]+
526+
Matcher.cast("<filter-function> | <uri>").plus(),
527+
528+
"<position>":
529+
// <position> = [
530+
// [ left | center | right | top | bottom | <percentage> | <length> ]
531+
// |
532+
// [ left | center | right | <percentage> | <length> ]
533+
// [ top | center | bottom | <percentage> | <length> ]
534+
// |
535+
// [ center | [ left | right ] [ <percentage> | <length> ]? ] &&
536+
// [ center | [ top | bottom ] [ <percentage> | <length> ]? ]
537+
//]
538+
Matcher.alt(
539+
// Because `alt` combinator is ordered, we need to test these
540+
// in order from longest possible match to shortest.
541+
Matcher.andand(
542+
Matcher.cast("center").or(
543+
Matcher.seq("left | right",
544+
Matcher.cast("<percentage> | <length>").question())),
545+
Matcher.cast("center").or(
546+
Matcher.seq("top | bottom",
547+
Matcher.cast("<percentage> | <length>").question()))),
548+
Matcher.seq("left | center | right | <percentage> | <length>",
549+
"top | center | bottom | <percentage> | <length>"),
550+
"left | center | right | top | bottom | <percentage> | <length>"
551+
),
552+
553+
"<repeat-style>":
554+
//repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2}
555+
Matcher.alt("repeat-x | repeat-y", Matcher.cast("repeat | space | round | no-repeat").braces(1,2)),
556+
557+
"<shadow>":
558+
//inset? && [ <length>{2,4} && <color>? ]
559+
Matcher.many([true /* length is required */],
560+
Matcher.cast("<length>").braces(2,4), "inset", "<color>"),
561+
562+
"<x-one-radius>":
563+
//[ <length> | <percentage> ] [ <length> | <percentage> ]?
564+
Matcher.cast("<length> | <percentage>").braces(1,2),
565+
566+
"<flex>":
567+
// http://www.w3.org/TR/2014/WD-css-flexbox-1-20140325/#flex-property
568+
// none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]
569+
// Valid syntaxes, according to https://developer.mozilla.org/en-US/docs/Web/CSS/flex#Syntax
570+
// * none
571+
// * <flex-grow>
572+
// * <flex-basis>
573+
// * <flex-grow> <flex-basis>
574+
// * <flex-grow> <flex-shrink>
575+
// * <flex-grow> <flex-shrink> <flex-basis>
576+
// * inherit
577+
Matcher.alt("none", "inherit", Matcher.cast("<flex-grow>").then(Matcher.cast("<flex-shrink>").question()).oror("<flex-basis>")),
578+
579+
"<text-decoration>":
580+
// none | [ underline || overline || line-through || blink ] | inherit
581+
Matcher.oror("underline", "overline", "line-through", "blink")
782582
}
783583
};

0 commit comments

Comments
 (0)