Skip to content

Commit

Permalink
implement ::slotted()
Browse files Browse the repository at this point in the history
  • Loading branch information
lahmatiy committed Jan 15, 2017
1 parent 58175e6 commit bbbfb0d
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 5 deletions.
92 changes: 91 additions & 1 deletion lib/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,82 @@ function getSimpleSelector(nested, relative) {
};
}

function getCompoundSelector(nested) {
var start = scanner.tokenStart;
var children = new List();
var child;

readSC();

scan:
while (!scanner.eof) {
switch (scanner.tokenType) {
case COMMA:
break scan;

case LEFTCURLYBRACKET:
if (nested) {
scanner.error();
}

break scan;

case RIGHTPARENTHESIS:
if (!nested) {
scanner.error();
}

break scan;

case COMMENT:
scanner.next();
continue;

case WHITESPACE:
readSC();
break scan;

case FULLSTOP:
child = getClass();
break;

case LEFTSQUAREBRACKET:
child = getAttribute();
break;

case NUMBERSIGN:
child = getId();
break;

case COLON:
child = getPseudo();
break;

case HYPHENMINUS:
case IDENTIFIER:
case ASTERISK:
case VERTICALLINE:
child = getTypeOrUniversal();
break;

default:
scanner.error();
}

children.appendData(child);
}

if (children.isEmpty()) {
scanner.error('Simple selector expected');
}

return {
type: 'SimpleSelector',
info: getInfo(start),
children: children
};
}

function getBlock() {
var start = scanner.tokenStart;
var children = new List();
Expand Down Expand Up @@ -1685,14 +1761,27 @@ function getPseudo() {
// :: ident
function getPseudoElement() {
var start = scanner.tokenStart;
var name;
var children = null;

scanner.eat(COLON);
scanner.eat(COLON);

// https://drafts.csswg.org/css-scoping/#slotted-pseudo
if (scanner.lookupValue(0, 'slotted')) {
name = readIdent(false);
scanner.eat(LEFTPARENTHESIS);
children = new List().appendData(getCompoundSelector(true));
scanner.eat(RIGHTPARENTHESIS);
} else {
name = readIdent(false);
}

return {
type: 'PseudoElement',
info: getInfo(start),
name: readIdent(false),
name: name,
children: children,
legacy: false
};
}
Expand All @@ -1711,6 +1800,7 @@ function getLegacyPseudoElement() {
type: 'PseudoElement',
info: getInfo(start),
name: readIdent(false),
children: null,
legacy: true
};
}
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ function translate(node) {
case 'PseudoElement':
return node.legacy
? ':' + node.name // :before, :after, :first-letter and :first-line
: '::' + node.name;
: node.children !== null
? '::' + node.name + '(' + each(node.children) + ')'
: '::' + node.name;

case 'Class':
return '.' + node.name;
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/translateWithSourceMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ function translate(node) {
case 'PseudoElement':
return node.legacy
? ':' + node.name // :before, :after, :first-letter and :first-line
: '::' + node.name;
: node.children !== null
? '::' + node.name + '(' + each(node.children) + ')'
: '::' + node.name;

case 'Class':
return '.' + node.name;
Expand Down
12 changes: 10 additions & 2 deletions lib/utils/walk.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ function walk(walk, node) {
}
break;

case 'PseudoElement':
if (node.children !== null) {
this['function'] = node;

node.children.each(walk, this);

this['function'] = null;
}
break;

case 'Function':
this['function'] = node;

Expand Down Expand Up @@ -208,8 +218,6 @@ function walk(walk, node) {
// case 'Class':
// case 'Id':
// case 'Percentage':
// case 'PseudoClass':
// case 'PseudoElement':
// case 'Space':
// case 'Number':
// case 'String':
Expand Down
8 changes: 8 additions & 0 deletions test/fixture/parse/simpleSelector/PseudoElement.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"ast": {
"type": "PseudoElement",
"name": "test",
"children": null,
"legacy": false
}
},
Expand All @@ -12,6 +13,7 @@
"ast": {
"type": "PseudoElement",
"name": "test-test",
"children": null,
"legacy": false
}
},
Expand All @@ -20,6 +22,7 @@
"ast": {
"type": "PseudoElement",
"name": "before",
"children": null,
"legacy": false
}
},
Expand All @@ -28,6 +31,7 @@
"ast": {
"type": "PseudoElement",
"name": "before",
"children": null,
"legacy": true
}
},
Expand All @@ -36,6 +40,7 @@
"ast": {
"type": "PseudoElement",
"name": "bEfOrE",
"children": null,
"legacy": true
}
},
Expand All @@ -44,6 +49,7 @@
"ast": {
"type": "PseudoElement",
"name": "after",
"children": null,
"legacy": true
}
},
Expand All @@ -52,6 +58,7 @@
"ast": {
"type": "PseudoElement",
"name": "first-letter",
"children": null,
"legacy": true
}
},
Expand All @@ -60,6 +67,7 @@
"ast": {
"type": "PseudoElement",
"name": "first-line",
"children": null,
"legacy": true
}
}
Expand Down
99 changes: 99 additions & 0 deletions test/fixture/parse/simpleSelector/pseudo-slotted.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"basic": {
"source": "::slotted(test)",
"ast": {
"type": "PseudoElement",
"name": "slotted",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Type",
"name": "test"
}
]
}
],
"legacy": false
}
},
"spaces around selector": {
"source": "::slotted( .a.b )",
"translate": "::slotted(.a.b)",
"ast": {
"type": "PseudoElement",
"name": "slotted",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "a"
},
{
"type": "Class",
"name": "b"
}
]
}
],
"legacy": false
}
},
"should be case insensitive": {
"source": "::SloTted(.a)",
"ast": {
"type": "PseudoElement",
"name": "SloTted",
"children": [
{
"type": "SimpleSelector",
"children": [
{
"type": "Class",
"name": "a"
}
]
}
],
"legacy": false
}
},
"error #1": {
"source": "::slotted(.a{)",
"offset": " ^",
"error": "Unexpected input"
},
"error #2": {
"source": "::slotted(,.b)",
"offset": " ^",
"error": "Simple selector expected"
},
"error #3": {
"source": "::slotted(.a,)",
"offset": " ^",
"error": "RightParenthesis is expected"
},
"error #4": {
"source": "::slotted(--test)",
"offset": " ^",
"error": "Identifier is expected"
},
"error #5": {
"source": "::slotted(var(--test))",
"offset": " ^",
"error": "Unexpected input"
},
"error #6": {
"source": "::slotted(> test)",
"offset": " ^",
"error": "Unexpected input"
},
"error #7": {
"source": "::slotted(foo,bar)",
"offset": " ^",
"error": "RightParenthesis is expected"
}
}

0 comments on commit bbbfb0d

Please sign in to comment.