-
-
Save lahmatiy/8bd89a7f2a4b9205157d0b807f0d170e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function isSelector(node) { | |
return node.type === 'TypeSelector' || | |
node.type === 'IdSelector' || | |
node.type === 'ClassSelector' || | |
node.type === 'AttributeSelector' || | |
node.type === 'PseudoClassSelector' || | |
node.type === 'PseudoElementSelector'; | |
} | |
function isLegacyPseudoElement(node) { | |
var name = node.name.toLowerCase(); | |
return name === 'before' || | |
name === 'after' || | |
name === 'first-letter' || | |
name === 'first-line'; | |
} | |
function validateSelector(selector, allowRelativeSelector) { | |
var lastCombinator = null; | |
var lastPseudoElement = null; | |
var lastSimpleSelector = null; | |
selector.each(function(node, item) { | |
if (node.type === 'Combinator') { | |
if (lastSimpleSelector !== null && !allowRelativeSelector) { | |
throw new Error('Selector can\'t starts with a combinator'); | |
} | |
if (lastCombinator !== null && lastCombinator.type !== 'WhiteSpace') { | |
throw new Error('Combinator can\'t be followed by a combinator'); | |
} | |
lastCombinator = node; | |
return; | |
} | |
if (node.type === 'WhiteSpace') { | |
if (lastSimpleSelector !== null && lastCombinator === null) { | |
lastCombinator = node; | |
} | |
return; | |
} | |
lastCombinator = null; | |
lastSimpleSelector = node; | |
switch (node.type) { | |
case 'TypeSelector': | |
if (item.prev !== null && isSelector(item.prev.data)) { | |
throw new Error('A compound selector can contain at most one type selector, and if it does, that must be the first simple selector in it'); | |
} | |
if (lastPseudoElement !== null) { | |
throw new Error(node.type + ' can\'t be used after pseudo-element'); | |
} | |
break; | |
case 'IdSelector': | |
case 'ClassSelector': | |
case 'AttributeSelector': | |
if (lastPseudoElement !== null) { | |
throw new Error(node.type + ' can\'t be used after pseudo-element'); | |
} | |
break; | |
case 'PseudoClassSelector': | |
if (isLegacyPseudoElement(node.name)) { | |
lastPseudoElement = node; | |
} | |
break; | |
case 'PseudoElementSelector': | |
lastPseudoElement = node; | |
break; | |
default: | |
throw new Error('Unexpected node type: ' + node.type); | |
} | |
}); | |
if (lastCombinator !== null) { | |
throw new Error('Trailing combinator'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment