Spaces:
Running
Running
var Marker = require('../../tokenizer/marker'); | |
var Selector = { | |
ADJACENT_SIBLING: '+', | |
DESCENDANT: '>', | |
DOT: '.', | |
HASH: '#', | |
NON_ADJACENT_SIBLING: '~', | |
PSEUDO: ':' | |
}; | |
var LETTER_PATTERN = /[a-zA-Z]/; | |
var NOT_PREFIX = ':not('; | |
var SEPARATOR_PATTERN = /[\s,(>~+]/; | |
function specificity(selector) { | |
var result = [0, 0, 0]; | |
var character; | |
var isEscaped; | |
var isSingleQuoted; | |
var isDoubleQuoted; | |
var roundBracketLevel = 0; | |
var couldIntroduceNewTypeSelector; | |
var withinNotPseudoClass = false; | |
var wasPseudoClass = false; | |
var i, l; | |
for (i = 0, l = selector.length; i < l; i++) { | |
character = selector[i]; | |
if (isEscaped) { | |
// noop | |
} else if (character == Marker.SINGLE_QUOTE && !isDoubleQuoted && !isSingleQuoted) { | |
isSingleQuoted = true; | |
} else if (character == Marker.SINGLE_QUOTE && !isDoubleQuoted && isSingleQuoted) { | |
isSingleQuoted = false; | |
} else if (character == Marker.DOUBLE_QUOTE && !isDoubleQuoted && !isSingleQuoted) { | |
isDoubleQuoted = true; | |
} else if (character == Marker.DOUBLE_QUOTE && isDoubleQuoted && !isSingleQuoted) { | |
isDoubleQuoted = false; | |
} else if (isSingleQuoted || isDoubleQuoted) { | |
continue; | |
} else if (roundBracketLevel > 0 && !withinNotPseudoClass) { | |
// noop | |
} else if (character == Marker.OPEN_ROUND_BRACKET) { | |
roundBracketLevel++; | |
} else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1) { | |
roundBracketLevel--; | |
withinNotPseudoClass = false; | |
} else if (character == Marker.CLOSE_ROUND_BRACKET) { | |
roundBracketLevel--; | |
} else if (character == Selector.HASH) { | |
result[0]++; | |
} else if (character == Selector.DOT || character == Marker.OPEN_SQUARE_BRACKET) { | |
result[1]++; | |
} else if (character == Selector.PSEUDO && !wasPseudoClass && !isNotPseudoClass(selector, i)) { | |
result[1]++; | |
withinNotPseudoClass = false; | |
} else if (character == Selector.PSEUDO) { | |
withinNotPseudoClass = true; | |
} else if ((i === 0 || couldIntroduceNewTypeSelector) && LETTER_PATTERN.test(character)) { | |
result[2]++; | |
} | |
isEscaped = character == Marker.BACK_SLASH; | |
wasPseudoClass = character == Selector.PSEUDO; | |
couldIntroduceNewTypeSelector = !isEscaped && SEPARATOR_PATTERN.test(character); | |
} | |
return result; | |
} | |
function isNotPseudoClass(selector, index) { | |
return selector.indexOf(NOT_PREFIX, index) === index; | |
} | |
module.exports = specificity; | |