78 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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;
 |