vendor: 9,918 bytes, lines 1-314
1/** 2 * Srcset Parser 3 * 4 * By Alex Bell | MIT License 5 * 6 * JS Parser for the string value that appears in markup <img srcset="here"> 7 * 8 * @returns Array [{url: _, d: _, w: _, h:_}, ...] 9 * 10 * Based super duper closely on the reference algorithm at: 11 * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute 12 * 13 * Most comments are copied in directly from the spec 14 * (except for comments in parens). 15 */ 16 17// 1. Let input be the value passed to this algorithm. 18function parseSrcset(input) { 19 20 // UTILITY FUNCTIONS 21 22 // Manual is faster than RegEx 23 // http://bjorn.tipling.com/state-and-regular-expressions-in-javascript 24 // http://jsperf.com/whitespace-character/5 25 function isSpace(c) { 26 return (c === "\u0020" || // space 27 c === "\u0009" || // horizontal tab 28 c === "\u000A" || // new line 29 c === "\u000C" || // form feed 30 c === "\u000D"); // carriage return 31 } 32 33 function collectCharacters(regEx) { 34 var chars, 35 match = regEx.exec(input.substring(pos)); 36 if (match) { 37 chars = match[ 0 ]; 38 pos += chars.length; 39 return chars; 40 } 41 } 42 43 var inputLength = input.length, 44 45 // (Don't use \s, to avoid matching non-breaking space) 46 regexLeadingSpaces = /^[ \t\n\r\u000c]+/, 47 regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/, 48 regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/, 49 regexTrailingCommas = /[,]+$/, 50 regexNonNegativeInteger = /^\d+$/, 51 52 // ( Positive or negative or unsigned integers or decimals, without or without exponents. 53 // Must include at least one digit. 54 // According to spec tests any decimal point must be followed by a digit. 55 // No leading plus sign is allowed.) 56 // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number 57 regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/, 58 59 url, 60 descriptors, 61 currentDescriptor, 62 state, 63 c, 64 65 // 2. Let position be a pointer into input, initially pointing at the start 66 // of the string. 67 pos = 0, 68 69 // 3. Let candidates be an initially empty source set. 70 candidates = []; 71 72 // 4. Splitting loop: Collect a sequence of characters that are space 73 // characters or U+002C COMMA characters. If any U+002C COMMA characters 74 // were collected, that is a parse error. 75 while (true) { 76 collectCharacters(regexLeadingCommasOrSpaces); 77 78 // 5. If position is past the end of input, return candidates and abort these steps. 79 if (pos >= inputLength) { 80 return candidates; // (we're done, this is the sole return path) 81 } 82 83 // 6. Collect a sequence of characters that are not space characters, 84 // and let that be url. 85 url = collectCharacters(regexLeadingNotSpaces); 86 87 // 7. Let descriptors be a new empty list. 88 descriptors = []; 89 90 // 8. If url ends with a U+002C COMMA character (,), follow these substeps: 91 // (1). Remove all trailing U+002C COMMA characters from url. If this removed 92 // more than one character, that is a parse error. 93 if (url.slice(-1) === ",") { 94 url = url.replace(regexTrailingCommas, ""); 95 // (Jump ahead to step 9 to skip tokenization and just push the candidate). 96 parseDescriptors(); 97 98 // Otherwise, follow these substeps: 99 } else { 100 tokenize(); 101 } // (close else of step 8) 102 103 // 16. Return to the step labeled splitting loop. 104 } // (Close of big while loop.) 105 106 /** 107 * Tokenizes descriptor properties prior to parsing 108 * Returns undefined. 109 */ 110 function tokenize() { 111 112 // 8.1. Descriptor tokeniser: Skip whitespace 113 collectCharacters(regexLeadingSpaces); 114 115 // 8.2. Let current descriptor be the empty string. 116 currentDescriptor = ""; 117 118 // 8.3. Let state be in descriptor. 119 state = "in descriptor"; 120 121 while (true) { 122 123 // 8.4. Let c be the character at position. 124 c = input.charAt(pos); 125 126 // Do the following depending on the value of state. 127 // For the purpose of this step, "EOF" is a special character representing 128 // that position is past the end of input. 129 130 // In descriptor 131 if (state === "in descriptor") { 132 // Do the following, depending on the value of c: 133 134 // Space character 135 // If current descriptor is not empty, append current descriptor to 136 // descriptors and let current descriptor be the empty string. 137 // Set state to after descriptor. 138 if (isSpace(c)) { 139 if (currentDescriptor) { 140 descriptors.push(currentDescriptor); 141 currentDescriptor = ""; 142 state = "after descriptor"; 143 } 144 145 // U+002C COMMA (,) 146 // Advance position to the next character in input. If current descriptor 147 // is not empty, append current descriptor to descriptors. Jump to the step 148 // labeled descriptor parser. 149 } else if (c === ",") { 150 pos += 1; 151 if (currentDescriptor) { 152 descriptors.push(currentDescriptor); 153 } 154 parseDescriptors(); 155 return; 156 157 // U+0028 LEFT PARENTHESIS (() 158 // Append c to current descriptor. Set state to in parens. 159 } else if (c === "\u0028") { 160 currentDescriptor = currentDescriptor + c; 161 state = "in parens"; 162 163 // EOF 164 // If current descriptor is not empty, append current descriptor to 165 // descriptors. Jump to the step labeled descriptor parser. 166 } else if (c === "") { 167 if (currentDescriptor) { 168 descriptors.push(currentDescriptor); 169 } 170 parseDescriptors(); 171 return; 172 173 // Anything else 174 // Append c to current descriptor. 175 } else { 176 currentDescriptor = currentDescriptor + c; 177 } 178 // (end "in descriptor" 179 180 // In parens 181 } else if (state === "in parens") { 182 183 // U+0029 RIGHT PARENTHESIS ()) 184 // Append c to current descriptor. Set state to in descriptor. 185 if (c === ")") { 186 currentDescriptor = currentDescriptor + c; 187 state = "in descriptor"; 188 189 // EOF 190 // Append current descriptor to descriptors. Jump to the step labeled 191 // descriptor parser. 192 } else if (c === "") { 193 descriptors.push(currentDescriptor); 194 parseDescriptors(); 195 return; 196 197 // Anything else 198 // Append c to current descriptor. 199 } else { 200 currentDescriptor = currentDescriptor + c; 201 } 202 203 // After descriptor 204 } else if (state === "after descriptor") { 205 206 // Do the following, depending on the value of c: 207 // Space character: Stay in this state. 208 if (isSpace(c)) { 209 210 // EOF: Jump to the step labeled descriptor parser. 211 } else if (c === "") { 212 parseDescriptors(); 213 return; 214 215 // Anything else 216 // Set state to in descriptor. Set position to the previous character in input. 217 } else { 218 state = "in descriptor"; 219 pos -= 1; 220 221 } 222 } 223 224 // Advance position to the next character in input. 225 pos += 1; 226 227 // Repeat this step. 228 } // (close while true loop) 229 } 230 231 /** 232 * Adds descriptor properties to a candidate, pushes to the candidates array 233 * @return undefined 234 */ 235 // Declared outside of the while loop so that it's only created once. 236 function parseDescriptors() { 237 238 // 9. Descriptor parser: Let error be no. 239 var pError = false, 240 241 // 10. Let width be absent. 242 // 11. Let density be absent. 243 // 12. Let future-compat-h be absent. (We're implementing it now as h) 244 w, d, h, i, 245 candidate = {}, 246 desc, lastChar, value, intVal, floatVal; 247 248 // 13. For each descriptor in descriptors, run the appropriate set of steps 249 // from the following list: 250 for (i = 0 ; i < descriptors.length; i++) { 251 desc = descriptors[ i ]; 252 253 lastChar = desc[ desc.length - 1 ]; 254 value = desc.substring(0, desc.length - 1); 255 intVal = parseInt(value, 10); 256 floatVal = parseFloat(value); 257 258 // If the descriptor consists of a valid non-negative integer followed by 259 // a U+0077 LATIN SMALL LETTER W character 260 if (regexNonNegativeInteger.test(value) && (lastChar === "w")) { 261 262 // If width and density are not both absent, then let error be yes. 263 if (w || d) {pError = true;} 264 265 // Apply the rules for parsing non-negative integers to the descriptor. 266 // If the result is zero, let error be yes. 267 // Otherwise, let width be the result. 268 if (intVal === 0) {pError = true;} else {w = intVal;} 269 270 // If the descriptor consists of a valid floating-point number followed by 271 // a U+0078 LATIN SMALL LETTER X character 272 } else if (regexFloatingPoint.test(value) && (lastChar === "x")) { 273 274 // If width, density and future-compat-h are not all absent, then let error 275 // be yes. 276 if (w || d || h) {pError = true;} 277 278 // Apply the rules for parsing floating-point number values to the descriptor. 279 // If the result is less than zero, let error be yes. Otherwise, let density 280 // be the result. 281 if (floatVal < 0) {pError = true;} else {d = floatVal;} 282 283 // If the descriptor consists of a valid non-negative integer followed by 284 // a U+0068 LATIN SMALL LETTER H character 285 } else if (regexNonNegativeInteger.test(value) && (lastChar === "h")) { 286 287 // If height and density are not both absent, then let error be yes. 288 if (h || d) {pError = true;} 289 290 // Apply the rules for parsing non-negative integers to the descriptor. 291 // If the result is zero, let error be yes. Otherwise, let future-compat-h 292 // be the result. 293 if (intVal === 0) {pError = true;} else {h = intVal;} 294 295 // Anything else, Let error be yes. 296 } else {pError = true;} 297 } // (close step 13 for loop) 298 299 // 15. If error is still no, then append a new image source to candidates whose 300 // URL is url, associated with a width width if not absent and a pixel 301 // density density if not absent. Otherwise, there is a parse error. 302 if (!pError) { 303 candidate.url = url; 304 if (w) { candidate.w = w;} 305 if (d) { candidate.d = d;} 306 if (h) { candidate.h = h;} 307 candidates.push(candidate); 308 } else if (window && window.console && console.log) { 309 console.log("Invalid srcset descriptor found in '" + 310 input + "' at '" + desc + "'."); 311 } 312 } // (close parseDescriptors fn) 313 314}
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.