| 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; |