You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.4 KiB
77 lines
2.4 KiB
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;
|
|
|