1/* 2--- 3name: Slick.Parser 4description: Standalone CSS3 Selector parser 5provides: Slick.Parser 6... 7*/ 8 9;(function(){ 10 11var parsed, 12 separatorIndex, 13 combinatorIndex, 14 reversed, 15 cache = {}, 16 reverseCache = {}, 17 reUnescape = /\\/g; 18 19var parse = function(expression, isReversed){ 20 if (expression == null) return null; 21 if (expression.Slick === true) return expression; 22 expression = ('' + expression).replace(/^\s+|\s+$/g, ''); 23 reversed = !!isReversed; 24 var currentCache = (reversed) ? reverseCache : cache; 25 if (currentCache[expression]) return currentCache[expression]; 26 parsed = { 27 Slick: true, 28 expressions: [], 29 raw: expression, 30 reverse: function(){ 31 return parse(this.raw, true); 32 } 33 }; 34 separatorIndex = -1; 35 while (expression != (expression = expression.replace(regexp, parser))); 36 parsed.length = parsed.expressions.length; 37 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed; 38}; 39 40var reverseCombinator = function(combinator){ 41 if (combinator === '!') return ' '; 42 else if (combinator === ' ') return '!'; 43 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, ''); 44 else return '!' + combinator; 45}; 46 47var reverse = function(expression){ 48 var expressions = expression.expressions; 49 for (var i = 0; i < expressions.length; i++){ 50 var exp = expressions[i]; 51 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)}; 52 53 for (var j = 0; j < exp.length; j++){ 54 var cexp = exp[j]; 55 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' '; 56 cexp.combinator = cexp.reverseCombinator; 57 delete cexp.reverseCombinator; 58 } 59 60 exp.reverse().push(last); 61 } 62 return expression; 63}; 64 65var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License 66 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ 67 return '\\' + match; 68 }); 69}; 70 71var regexp = new RegExp( 72/* 73#!/usr/bin/env ruby 74puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'') 75__END__ 76 "(?x)^(?:\ 77 \\s* ( , ) \\s* # Separator \n\ 78 | \\s* ( <combinator>+ ) \\s* # Combinator \n\ 79 | ( \\s+ ) # CombinatorChildren \n\ 80 | ( <unicode>+ | \\* ) # Tag \n\ 81 | \\# ( <unicode>+ ) # ID \n\ 82 | \\. ( <unicode>+ ) # ClassName \n\ 83 | # Attribute \n\ 84 \\[ \ 85 \\s* (<unicode1>+) (?: \ 86 \\s* ([*^$!~|]?=) (?: \ 87 \\s* (?:\ 88 ([\"']?)(.*?)\\9 \ 89 )\ 90 ) \ 91 )? \\s* \ 92 \\](?!\\]) \n\ 93 | :+ ( <unicode>+ )(?:\ 94 \\( (?:\ 95 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\ 96 ) \\)\ 97 )?\ 98 )" 99*/ 100 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)" 101 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']') 102 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') 103 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') 104); 105 106function parser( 107 rawMatch, 108 109 separator, 110 combinator, 111 combinatorChildren, 112 113 tagName, 114 id, 115 className, 116 117 attributeKey, 118 attributeOperator, 119 attributeQuote, 120 attributeValue, 121 122 pseudoMarker, 123 pseudoClass, 124 pseudoQuote, 125 pseudoClassQuotedValue, 126 pseudoClassValue 127){ 128 if (separator || separatorIndex === -1){ 129 parsed.expressions[++separatorIndex] = []; 130 combinatorIndex = -1; 131 if (separator) return ''; 132 } 133 134 if (combinator || combinatorChildren || combinatorIndex === -1){ 135 combinator = combinator || ' '; 136 var currentSeparator = parsed.expressions[separatorIndex]; 137 if (reversed && currentSeparator[combinatorIndex]) 138 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator); 139 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'}; 140 } 141 142 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex]; 143 144 if (tagName){ 145 currentParsed.tag = tagName.replace(reUnescape, ''); 146 147 } else if (id){ 148 currentParsed.id = id.replace(reUnescape, ''); 149 150 } else if (className){ 151 className = className.replace(reUnescape, ''); 152 153 if (!currentParsed.classList) currentParsed.classList = []; 154 if (!currentParsed.classes) currentParsed.classes = []; 155 currentParsed.classList.push(className); 156 currentParsed.classes.push({ 157 value: className, 158 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)') 159 }); 160 161 } else if (pseudoClass){ 162 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue; 163 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null; 164 165 if (!currentParsed.pseudos) currentParsed.pseudos = []; 166 currentParsed.pseudos.push({ 167 key: pseudoClass.replace(reUnescape, ''), 168 value: pseudoClassValue, 169 type: pseudoMarker.length == 1 ? 'class' : 'element'
170 }); 171 172 } else if (attributeKey){ 173 attributeKey = attributeKey.replace(reUnescape, ''); 174 attributeValue = (attributeValue || '').replace(reUnescape, ''); 175 176 var test, regexp; 177 178 switch (attributeOperator){ 179 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break; 180 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break; 181 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break; 182 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break; 183 case '=' : test = function(value){ 184 return attributeValue == value; 185 }; break; 186 case '*=' : test = function(value){ 187 return value && value.indexOf(attributeValue) > -1; 188 }; break; 189 case '!=' : test = function(value){ 190 return attributeValue != value; 191 }; break; 192 default : test = function(value){ 193 return !!value; 194 }; 195 } 196 197 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){ 198 return false; 199 }; 200 201 if (!test) test = function(value){ 202 return value && regexp.test(value); 203 }; 204 205 if (!currentParsed.attributes) currentParsed.attributes = []; 206 currentParsed.attributes.push({ 207 key: attributeKey, 208 operator: attributeOperator, 209 value: attributeValue, 210 test: test 211 }); 212 213 } 214 215 return ''; 216}; 217 218// Slick NS 219 220var Slick = (this.Slick || {}); 221 222Slick.parse = function(expression){ 223 return parse(expression); 224}; 225 226Slick.escapeRegExp = escapeRegExp; 227 228if (!this.Slick) this.Slick = Slick; 229 230}).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.