Skip to content

Commit

Permalink
add support for :has()
Browse files Browse the repository at this point in the history
  • Loading branch information
lahmatiy committed Jan 14, 2017
1 parent 07942ae commit 01813eb
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 30 deletions.
21 changes: 15 additions & 6 deletions lib/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ var filename;
var DESCENDANT_COMBINATOR = {};
var SPACE_NODE = { type: 'Space' };
var NESTED = true;
var ABSOLUTE = false;
var RELATIVE = true;

var WHITESPACE = Scanner.TYPE.Whitespace;
var IDENTIFIER = Scanner.TYPE.Identifier;
Expand Down Expand Up @@ -53,7 +55,8 @@ var SCOPE_ATRULE_EXPRESSION = {
var SCOPE_SELECTOR = {
url: getUri,
not: getSelectorFunction,
matches: getSelectorFunction
matches: getSelectorFunction,
has: getRelativeSelectorFunction
};
var SCOPE_VALUE = {
url: getUri,
Expand Down Expand Up @@ -252,7 +255,7 @@ function getRule() {
return node;
}

function getSelector(nested) {
function getSelector(nested, relative) {
var start = scanner.tokenStart;
var children = new List();
var simpleSelector;
Expand Down Expand Up @@ -285,7 +288,7 @@ function getSelector(nested) {

default:
lastComma = -1;
simpleSelector = getSimpleSelector(nested);
simpleSelector = getSimpleSelector(nested, relative);
children.appendData(simpleSelector);

if (simpleSelector.children.isEmpty()) {
Expand All @@ -305,7 +308,7 @@ function getSelector(nested) {
};
}

function getSimpleSelector(nested) {
function getSimpleSelector(nested, relative) {
var start = scanner.tokenStart;
var children = new List();
var combinator = null;
Expand Down Expand Up @@ -349,7 +352,7 @@ function getSimpleSelector(nested) {
case GREATERTHANSIGN:
case TILDE:
case SOLIDUS:
if ((children.head === null) || // combinator in the beginning
if ((children.head === null && !relative) || // combinator in the beginning
(combinator !== null && combinator !== DESCENDANT_COMBINATOR)) {
scanner.error('Unexpected combinator');
}
Expand Down Expand Up @@ -1068,7 +1071,13 @@ function getFunctionArguments(scope) {

function getSelectorFunction(scope, info, name) {
return getFunctionInternal(function() {
return new List().appendData(getSelector(true));
return new List().appendData(getSelector(NESTED, ABSOLUTE));
}, scope, info, name);
}

function getRelativeSelectorFunction(scope, info, name) {
return getFunctionInternal(function() {
return new List().appendData(getSelector(NESTED, RELATIVE));
}, scope, info, name);
}

Expand Down
212 changes: 212 additions & 0 deletions test/fixture/parse/simpleSelector/pseudo-has.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
{
"basic": {
"source": ":has(test)",
"ast": {
"type": "PseudoClass",
"name": "has",
"children": [
{
"type": "Selector",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Type",
"name": "test"
}
]
}
]
}
]
}
},
"negation with selector group": {
"source": ":has(.a,.b.c)",
"ast": {
"type": "PseudoClass",
"name": "has",
"children": [
{
"type": "Selector",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "a"
}
]
},
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "b"
},
{
"type": "Class",
"name": "c"
}
]
}
]
}
]
}
},
"selector group and spaces": {
"source": ":has( .a , .b )",
"translate": ":has(.a,.b)",
"ast": {
"type": "PseudoClass",
"name": "has",
"children": [
{
"type": "Selector",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "a"
}
]
},
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "b"
}
]
}
]
}
]
}
},
"should be case insensitive": {
"source": ":HaS(.a,.b)",
"ast": {
"type": "PseudoClass",
"name": "HaS",
"children": [
{
"type": "Selector",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "a"
}
]
},
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "b"
}
]
}
]
}
]
}
},
"should support relative selectors": {
"source": ":has(> .a,+.b)",
"translate": ":has(>.a,+.b)",
"ast": {
"type": "PseudoClass",
"name": "has",
"children": [
{
"type": "Selector",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Combinator",
"name": ">"
},
{
"type": "Class",
"name": "a"
}
]
},
{
"type": "SimpleSelector",
"children": [
{
"type": "Combinator",
"name": "+"
},
{
"type": "Class",
"name": "b"
}
]
}
]
}
]
}
},
"error #1": {
"source": ":has(.a{)",
"offset": " ^",
"error": "Unexpected input"
},
"error #2": {
"source": ":has(,.b)",
"offset": " ^",
"error": "Unexpected comma"
},
"error #3": {
"source": ":has(.a,)",
"offset": " ^",
"error": "Unexpected trailing comma"
},
"error #4": {
"source": ":has(.a,,)",
"offset": " ^",
"error": "Unexpected comma"
},
"error #5": {
"source": ":has(.a,.b{)",
"offset": " ^",
"error": "Unexpected input"
},
"error #6": {
"source": ":has(--test)",
"offset": " ^",
"error": "Identifier is expected"
},
"error #7": {
"source": ":has(var(--test))",
"offset": " ^",
"error": "Unexpected input"
},
"error #8": {
"source": ":has(>+a)",
"offset": " ^",
"error": "Unexpected combinator"
},
"error #9": {
"source": ":has(~foo, >+a)",
"offset": " ^",
"error": "Unexpected combinator"
}
}
34 changes: 22 additions & 12 deletions test/fixture/parse/simpleSelector/pseudo-matches.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"basic negation": {
"source": ":matches(el.class-postfix)",
"basic": {
"source": ":matches(test)",
"ast": {
"type": "PseudoClass",
"name": "matches",
Expand All @@ -13,11 +13,7 @@
"children": [
{
"type": "Type",
"name": "el"
},
{
"type": "Class",
"name": "class-postfix"
"name": "test"
}
]
}
Expand All @@ -26,8 +22,8 @@
]
}
},
"negation with selector group": {
"source": ":matches(.a,.b)",
"selector group": {
"source": ":matches(.a,.b.c)",
"ast": {
"type": "PseudoClass",
"name": "matches",
Expand All @@ -50,6 +46,10 @@
{
"type": "Class",
"name": "b"
},
{
"type": "Class",
"name": "c"
}
]
}
Expand All @@ -58,7 +58,7 @@
]
}
},
"negation with selector group and spaces": {
"selector group and spaces": {
"source": ":matches( .a , .b )",
"translate": ":matches(.a,.b)",
"ast": {
Expand Down Expand Up @@ -149,13 +149,23 @@
"error": "Unexpected input"
},
"error #6": {
"source": ":matches(--test) {}",
"source": ":matches(--test)",
"offset": " ^",
"error": "Identifier is expected"
},
"error #7": {
"source": ":matches(var(--test)) {}",
"source": ":matches(var(--test))",
"offset": " ^",
"error": "Unexpected input"
},
"error #8": {
"source": ":matches(> test)",
"offset": " ^",
"error": "Unexpected combinator"
},
"error #9": {
"source": ":matches(foo,> bar)",
"offset": " ^",
"error": "Unexpected combinator"
}
}
Loading

0 comments on commit 01813eb

Please sign in to comment.