| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 | var Marker = require('../../tokenizer/marker');var split = require('../../utils/split');var DEEP_SELECTOR_PATTERN = /\/deep\//;var DOUBLE_COLON_PATTERN = /^::/;var NOT_PSEUDO = ':not';var PSEUDO_CLASSES_WITH_ARGUMENTS = [  ':dir',  ':lang',  ':not',  ':nth-child',  ':nth-last-child',  ':nth-last-of-type',  ':nth-of-type'];var RELATION_PATTERN = /[>\+~]/;var UNMIXABLE_PSEUDO_CLASSES = [  ':after',  ':before',  ':first-letter',  ':first-line',  ':lang'];var UNMIXABLE_PSEUDO_ELEMENTS = [  '::after',  '::before',  '::first-letter',  '::first-line'];var Level = {  DOUBLE_QUOTE: 'double-quote',  SINGLE_QUOTE: 'single-quote',  ROOT: 'root'};function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {  var singleSelectors = split(selector, Marker.COMMA);  var singleSelector;  var i, l;  for (i = 0, l = singleSelectors.length; i < l; i++) {    singleSelector = singleSelectors[i];    if (singleSelector.length === 0 ||        isDeepSelector(singleSelector) ||        (singleSelector.indexOf(Marker.COLON) > -1 && !areMergeable(singleSelector, extractPseudoFrom(singleSelector), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging))) {      return false;    }  }  return true;}function isDeepSelector(selector) {  return DEEP_SELECTOR_PATTERN.test(selector);}function extractPseudoFrom(selector) {  var list = [];  var character;  var buffer = [];  var level = Level.ROOT;  var roundBracketLevel = 0;  var isQuoted;  var isEscaped;  var isPseudo = false;  var isRelation;  var wasColon = false;  var index;  var len;  for (index = 0, len = selector.length; index < len; index++) {    character = selector[index];    isRelation = !isEscaped && RELATION_PATTERN.test(character);    isQuoted = level == Level.DOUBLE_QUOTE || level == Level.SINGLE_QUOTE;    if (isEscaped) {      buffer.push(character);    } else if (character == Marker.DOUBLE_QUOTE && level == Level.ROOT) {      buffer.push(character);      level = Level.DOUBLE_QUOTE;    } else if (character == Marker.DOUBLE_QUOTE && level == Level.DOUBLE_QUOTE) {      buffer.push(character);      level = Level.ROOT;    } else if (character == Marker.SINGLE_QUOTE && level == Level.ROOT) {      buffer.push(character);      level = Level.SINGLE_QUOTE;    } else if (character == Marker.SINGLE_QUOTE && level == Level.SINGLE_QUOTE) {      buffer.push(character);      level = Level.ROOT;    } else if (isQuoted) {      buffer.push(character);    } else if (character == Marker.OPEN_ROUND_BRACKET) {      buffer.push(character);      roundBracketLevel++;    } else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1 && isPseudo) {      buffer.push(character);      list.push(buffer.join(''));      roundBracketLevel--;      buffer = [];      isPseudo = false;    } else if (character == Marker.CLOSE_ROUND_BRACKET) {      buffer.push(character);      roundBracketLevel--;    } else if (character == Marker.COLON && roundBracketLevel === 0 && isPseudo && !wasColon) {      list.push(buffer.join(''));      buffer = [];      buffer.push(character);    } else if (character == Marker.COLON && roundBracketLevel === 0 && !wasColon) {      buffer = [];      buffer.push(character);      isPseudo = true;    } else if (character == Marker.SPACE && roundBracketLevel === 0 && isPseudo) {      list.push(buffer.join(''));      buffer = [];      isPseudo = false;    } else if (isRelation && roundBracketLevel === 0 && isPseudo) {      list.push(buffer.join(''));      buffer = [];      isPseudo = false;    } else {      buffer.push(character);    }    isEscaped = character == Marker.BACK_SLASH;    wasColon = character == Marker.COLON;  }  if (buffer.length > 0 && isPseudo) {    list.push(buffer.join(''));  }  return list;}function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {  return areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) &&    needArguments(matches) &&    (matches.length < 2 || !someIncorrectlyChained(selector, matches)) &&    (matches.length < 2 || multiplePseudoMerging && allMixable(matches));}function areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) {  var match;  var name;  var i, l;  for (i = 0, l = matches.length; i < l; i++) {    match = matches[i];    name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?      match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET)) :      match;    if (mergeablePseudoClasses.indexOf(name) === -1 && mergeablePseudoElements.indexOf(name) === -1) {      return false;    }  }  return true;}function needArguments(matches) {  var match;  var name;  var bracketOpensAt;  var hasArguments;  var i, l;  for (i = 0, l = matches.length; i < l; i++) {    match = matches[i];    bracketOpensAt = match.indexOf(Marker.OPEN_ROUND_BRACKET);    hasArguments = bracketOpensAt > -1;    name = hasArguments ?      match.substring(0, bracketOpensAt) :      match;    if (hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) == -1) {      return false;    }    if (!hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) > -1) {      return false;    }  }  return true;}function someIncorrectlyChained(selector, matches) {  var positionInSelector = 0;  var match;  var matchAt;  var nextMatch;  var nextMatchAt;  var name;  var nextName;  var areChained;  var i, l;  for (i = 0, l = matches.length; i < l; i++) {    match = matches[i];    nextMatch = matches[i + 1];    if (!nextMatch) {      break;    }    matchAt = selector.indexOf(match, positionInSelector);    nextMatchAt = selector.indexOf(match, matchAt + 1);    positionInSelector = nextMatchAt;    areChained = matchAt + match.length == nextMatchAt;    if (areChained) {      name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?        match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET)) :        match;      nextName = nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET) > -1 ?        nextMatch.substring(0, nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET)) :        nextMatch;      if (name != NOT_PSEUDO || nextName != NOT_PSEUDO) {        return true;      }    }  }  return false;}function allMixable(matches) {  var unmixableMatches = 0;  var match;  var i, l;  for (i = 0, l = matches.length; i < l; i++) {    match = matches[i];    if (isPseudoElement(match)) {      unmixableMatches += UNMIXABLE_PSEUDO_ELEMENTS.indexOf(match) > -1 ? 1 : 0;    } else {      unmixableMatches += UNMIXABLE_PSEUDO_CLASSES.indexOf(match) > -1 ? 1 : 0;    }    if (unmixableMatches > 1) {      return false;    }  }  return true;}function isPseudoElement(pseudo) {  return DOUBLE_COLON_PATTERN.test(pseudo);}module.exports = isMergeable;
 |