├── .yarnrc.yml ├── .gitignore ├── package.json ├── license ├── readme.md ├── index.d.ts ├── .github └── workflows │ └── continuous-integration.yml ├── index.js └── test.js /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | defaultSemverRangePrefix: "" 2 | 3 | enableGlobalCache: true 4 | 5 | nodeLinker: node-modules 6 | 7 | yarnPath: .yarn/releases/yarn-3.2.2.cjs 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */.DS_Store 2 | .DS_Store 3 | .DS_Store? 4 | ._* 5 | .Spotlight-V100 6 | .Trashes 7 | 8 | node_modules 9 | *.log 10 | coverage 11 | 12 | # Yarn 2 13 | .yarn/cache/ 14 | .yarn/build-state.yml 15 | .yarn/install-state.gz 16 | .pnp.* 17 | 18 | yarn.lock 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prettier/parse-srcset", 3 | "version": "3.1.0", 4 | "description": "A spec-conformant JavaScript parser for the HTML5 srcset attribute", 5 | "exports": "./index.js", 6 | "files": [ 7 | "index.js", 8 | "index.d.ts" 9 | ], 10 | "type": "module", 11 | "directories": { 12 | "test": "tests" 13 | }, 14 | "scripts": { 15 | "test": "node --test", 16 | "test-coverage": "c8 node --test", 17 | "release": "np --yolo --no-yarn" 18 | }, 19 | "c8": { 20 | "reporter": [ 21 | "lcov", 22 | "text" 23 | ], 24 | "include": [ 25 | "src" 26 | ] 27 | }, 28 | "repository": "prettier/parse-srcset", 29 | "author": "Alex Bell ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/prettier/parse-srcset/issues" 33 | }, 34 | "homepage": "https://github.com/prettier/parse-srcset#readme", 35 | "publishConfig": { 36 | "access": "public", 37 | "registry": "https://registry.npmjs.org/" 38 | }, 39 | "devDependencies": { 40 | "c8": "8.0.0", 41 | "he": "1.2.0" 42 | }, 43 | "packageManager": "yarn@3.2.2" 44 | } 45 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alex Bell 4 | Copyright (c) fisker Cheung 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # @prettier/parse-srcset 2 | 3 | This repository is a fork of https://github.com/albell/parse-srcset for [Prettier](https://github.com/prettier/prettier). 4 | 5 | --- 6 | 7 | A javascript parser for the [HTML5 srcset](http://www.w3.org/TR/html-srcset/) attribute, based on the [WHATWG reference algorithm](https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute). It has an extensive test suite based on the [W3C srcset conformance checker](http://w3c-test.org/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html). 8 | 9 | ## Installation 10 | 11 | ```bash 12 | yarn add @prettier/parse-srcset 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```js 18 | import parseSrcset from "@prettier/parse-srcset"; 19 | 20 | parseSrcset('elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x'); 21 | /* 22 | [ 23 | { source: { value: 'elva-fairy-320w.jpg', startOffset: 0 } }, 24 | { 25 | source: { value: 'elva-fairy-480w.jpg', startOffset: 21 }, 26 | density: { value: 1.5 } 27 | }, 28 | { 29 | source: { value: 'elva-fairy-640w.jpg', startOffset: 47 }, 30 | density: { value: 2 } 31 | } 32 | ] 33 | */ 34 | ``` 35 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export type Candidate = { 2 | source: { 3 | value: string; 4 | startOffset: number; 5 | }; 6 | width?: { 7 | value: number; 8 | }; 9 | height?: { 10 | value: number; 11 | }; 12 | density?: { 13 | value: number; 14 | }; 15 | }; 16 | 17 | /** 18 | Parses the string value that appears in markup ``. 19 | 20 | @description A javascript parser for the [HTML5 srcset](http://www.w3.org/TR/html-srcset/) attribute, based on the [WHATWG reference algorithm](https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute). It has an extensive test suite based on the [W3C srcset conformance checker](http://w3c-test.org/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html) 21 | 22 | @param {string} input - The string value to parse. 23 | @returns {Candidate[]} An array of objects representing the image candidates. 24 | @throws {Error} If the input string is empty or does not contain any image candidate strings. 25 | 26 | @example 27 | ```ts 28 | import parseSrcset from "@prettier/parse-srcset"; 29 | 30 | parseSrcset('elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x'); 31 | // output: 32 | [ 33 | { source: { value: 'elva-fairy-320w.jpg', startOffset: 0 } }, 34 | { 35 | source: { value: 'elva-fairy-480w.jpg', startOffset: 21 }, 36 | density: { value: 1.5 } 37 | }, 38 | { 39 | source: { value: 'elva-fairy-640w.jpg', startOffset: 47 }, 40 | density: { value: 2 } 41 | } 42 | ] 43 | ``` 44 | */ 45 | export default function parseSrcset(input: string): Candidate[]; 46 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | # schedule: 9 | # - cron: "0 23 * * 6" 10 | 11 | jobs: 12 | test: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: 17 | - "ubuntu-latest" 18 | # - "macos-latest" 19 | # - "windows-latest" 20 | node_version: 21 | - "18" 22 | # exclude: 23 | # - os: "macos-latest" 24 | # node_version: "12" 25 | name: Node.js ${{ matrix.node_version }} on ${{ matrix.os }} 26 | runs-on: ${{ matrix.os }} 27 | env: 28 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v3 32 | 33 | - name: Setup Node.js 34 | uses: actions/setup-node@v3 35 | with: 36 | node-version: ${{ matrix.node_version }} 37 | 38 | - name: Install Dependencies 39 | run: yarn 40 | 41 | - name: Run Test 42 | run: yarn test 43 | 44 | # - name: Run Test 45 | # run: yarn test-coverage 46 | 47 | # - uses: codecov/codecov-action@v3 48 | # with: 49 | # fail_ci_if_error: true 50 | 51 | # lint: 52 | # name: Lint 53 | # runs-on: ubuntu-latest 54 | # env: 55 | # YARN_ENABLE_IMMUTABLE_INSTALLS: false 56 | # steps: 57 | # - name: Checkout 58 | # uses: actions/checkout@v3 59 | 60 | # - name: Setup Node.js 61 | # uses: actions/setup-node@v3 62 | 63 | # - name: Install Dependencies 64 | # run: yarn 65 | 66 | # - name: Run Lint 67 | # run: yarn lint 68 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Srcset Parser 3 | * 4 | * By Alex Bell | MIT License 5 | * 6 | * JS Parser for the string value that appears in markup 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 | function isASCIIWhitespace(character) { 18 | return ( 19 | // Horizontal tab 20 | character === "\u0009" || 21 | // New line 22 | character === "\u000A" || 23 | // Form feed 24 | character === "\u000C" || 25 | // Carriage return 26 | character === "\u000D" || 27 | // Space 28 | character === "\u0020" 29 | ); 30 | } 31 | 32 | // (Don't use \s, to avoid matching non-breaking space) 33 | // eslint-disable-next-line no-control-regex 34 | const regexLeadingSpaces = /^[ \t\n\r\u000c]+/; 35 | // eslint-disable-next-line no-control-regex 36 | const regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/; 37 | // eslint-disable-next-line no-control-regex 38 | const regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/; 39 | const regexTrailingCommas = /[,]+$/; 40 | const regexNonNegativeInteger = /^\d+$/; 41 | 42 | // ( Positive or negative or unsigned integers or decimals, without or without exponents. 43 | // Must include at least one digit. 44 | // According to spec tests any decimal point must be followed by a digit. 45 | // No leading plus sign is allowed.) 46 | // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number 47 | const regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/; 48 | 49 | function parseSrcset(input) { 50 | // 1. Let input be the value passed to this algorithm. 51 | const inputLength = input.length; 52 | 53 | let url; 54 | let descriptors; 55 | let currentDescriptor; 56 | let state; 57 | let c; 58 | 59 | // 2. Let position be a pointer into input, initially pointing at the start 60 | // of the string. 61 | let position = 0; 62 | let startOffset; 63 | 64 | function collectCharacters(regEx) { 65 | let chars; 66 | const match = regEx.exec(input.substring(position)); 67 | 68 | if (match) { 69 | [chars] = match; 70 | position += chars.length; 71 | 72 | return chars; 73 | } 74 | } 75 | 76 | // 3. Let candidates be an initially empty source set. 77 | const candidates = []; 78 | 79 | // 4. Splitting loop: Collect a sequence of characters that are space 80 | // characters or U+002C COMMA characters. If any U+002C COMMA characters 81 | // were collected, that is a parse error. 82 | while (true) { 83 | collectCharacters(regexLeadingCommasOrSpaces); 84 | 85 | // 5. If position is past the end of input, return candidates and abort these steps. 86 | if (position >= inputLength) { 87 | if (candidates.length === 0) { 88 | throw new Error("Must contain one or more image candidate strings."); 89 | } 90 | 91 | // (we're done, this is the sole return path) 92 | return candidates; 93 | } 94 | 95 | // 6. Collect a sequence of characters that are not space characters, 96 | // and let that be url. 97 | startOffset = position; 98 | url = collectCharacters(regexLeadingNotSpaces); 99 | 100 | // 7. Let descriptors be a new empty list. 101 | descriptors = []; 102 | 103 | // 8. If url ends with a U+002C COMMA character (,), follow these sub steps: 104 | // (1). Remove all trailing U+002C COMMA characters from url. If this removed 105 | // more than one character, that is a parse error. 106 | if (url.slice(-1) === ",") { 107 | url = url.replace(regexTrailingCommas, ""); 108 | 109 | // (Jump ahead to step 9 to skip tokenization and just push the candidate). 110 | parseDescriptors(); 111 | } 112 | // Otherwise, follow these sub steps: 113 | else { 114 | tokenize(); 115 | } 116 | 117 | // 16. Return to the step labeled splitting loop. 118 | } 119 | 120 | /** 121 | * Tokenizes descriptor properties prior to parsing 122 | * Returns undefined. 123 | */ 124 | function tokenize() { 125 | // 8.1. Descriptor tokenizer: Skip whitespace 126 | collectCharacters(regexLeadingSpaces); 127 | 128 | // 8.2. Let current descriptor be the empty string. 129 | currentDescriptor = ""; 130 | 131 | // 8.3. Let state be in descriptor. 132 | state = "in descriptor"; 133 | 134 | // eslint-disable-next-line no-constant-condition 135 | while (true) { 136 | // 8.4. Let c be the character at position. 137 | c = input.charAt(position); 138 | 139 | // Do the following depending on the value of state. 140 | // For the purpose of this step, "EOF" is a special character representing 141 | // that position is past the end of input. 142 | 143 | // In descriptor 144 | if (state === "in descriptor") { 145 | // Do the following, depending on the value of c: 146 | 147 | // Space character 148 | // If current descriptor is not empty, append current descriptor to 149 | // descriptors and let current descriptor be the empty string. 150 | // Set state to after descriptor. 151 | if (isASCIIWhitespace(c)) { 152 | if (currentDescriptor) { 153 | descriptors.push(currentDescriptor); 154 | currentDescriptor = ""; 155 | state = "after descriptor"; 156 | } 157 | } 158 | // U+002C COMMA (,) 159 | // Advance position to the next character in input. If current descriptor 160 | // is not empty, append current descriptor to descriptors. Jump to the step 161 | // labeled descriptor parser. 162 | else if (c === ",") { 163 | position += 1; 164 | 165 | if (currentDescriptor) { 166 | descriptors.push(currentDescriptor); 167 | } 168 | 169 | parseDescriptors(); 170 | 171 | return; 172 | } 173 | // U+0028 LEFT PARENTHESIS (() 174 | // Append c to current descriptor. Set state to in parens. 175 | else if (c === "\u0028") { 176 | currentDescriptor += c; 177 | state = "in parens"; 178 | } 179 | // EOF 180 | // If current descriptor is not empty, append current descriptor to 181 | // descriptors. Jump to the step labeled descriptor parser. 182 | else if (c === "") { 183 | if (currentDescriptor) { 184 | descriptors.push(currentDescriptor); 185 | } 186 | 187 | parseDescriptors(); 188 | 189 | return; 190 | 191 | // Anything else 192 | // Append c to current descriptor. 193 | } else { 194 | currentDescriptor += c; 195 | } 196 | } 197 | // In parens 198 | else if (state === "in parens") { 199 | // U+0029 RIGHT PARENTHESIS ()) 200 | // Append c to current descriptor. Set state to in descriptor. 201 | if (c === ")") { 202 | currentDescriptor += c; 203 | state = "in descriptor"; 204 | } 205 | // EOF 206 | // Append current descriptor to descriptors. Jump to the step labeled 207 | // descriptor parser. 208 | else if (c === "") { 209 | descriptors.push(currentDescriptor); 210 | parseDescriptors(); 211 | return; 212 | } 213 | // Anything else 214 | // Append c to current descriptor. 215 | else { 216 | currentDescriptor += c; 217 | } 218 | } 219 | // After descriptor 220 | else if (state === "after descriptor") { 221 | // Do the following, depending on the value of c: 222 | if (isASCIIWhitespace(c)) { 223 | // Space character: Stay in this state. 224 | } 225 | // EOF: Jump to the step labeled descriptor parser. 226 | else if (c === "") { 227 | parseDescriptors(); 228 | return; 229 | } 230 | // Anything else 231 | // Set state to in descriptor. Set position to the previous character in input. 232 | else { 233 | state = "in descriptor"; 234 | position -= 1; 235 | } 236 | } 237 | 238 | // Advance position to the next character in input. 239 | position += 1; 240 | } 241 | } 242 | 243 | /** 244 | * Adds descriptor properties to a candidate, pushes to the candidates array 245 | * @return undefined 246 | */ 247 | // Declared outside of the while loop so that it's only created once. 248 | function parseDescriptors() { 249 | // 9. Descriptor parser: Let error be no. 250 | let pError = false; 251 | 252 | // 10. Let width be absent. 253 | // 11. Let density be absent. 254 | // 12. Let future-compat-h be absent. (We're implementing it now as h) 255 | let w; 256 | let d; 257 | let h; 258 | let i; 259 | const candidate = {}; 260 | let desc; 261 | let lastChar; 262 | let value; 263 | let intVal; 264 | let floatVal; 265 | 266 | // 13. For each descriptor in descriptors, run the appropriate set of steps 267 | // from the following list: 268 | for (i = 0; i < descriptors.length; i++) { 269 | desc = descriptors[i]; 270 | 271 | lastChar = desc[desc.length - 1]; 272 | value = desc.substring(0, desc.length - 1); 273 | intVal = parseInt(value, 10); 274 | floatVal = parseFloat(value); 275 | 276 | // If the descriptor consists of a valid non-negative integer followed by 277 | // a U+0077 LATIN SMALL LETTER W character 278 | if (regexNonNegativeInteger.test(value) && lastChar === "w") { 279 | // If width and density are not both absent, then let error be yes. 280 | if (w || d) { 281 | pError = true; 282 | } 283 | 284 | // Apply the rules for parsing non-negative integers to the descriptor. 285 | // If the result is zero, let error be yes. 286 | // Otherwise, let width be the result. 287 | if (intVal === 0) { 288 | pError = true; 289 | } else { 290 | w = intVal; 291 | } 292 | } 293 | // If the descriptor consists of a valid floating-point number followed by 294 | // a U+0078 LATIN SMALL LETTER X character 295 | else if (regexFloatingPoint.test(value) && lastChar === "x") { 296 | // If width, density and future-compat-h are not all absent, then let error 297 | // be yes. 298 | if (w || d || h) { 299 | pError = true; 300 | } 301 | 302 | // Apply the rules for parsing floating-point number values to the descriptor. 303 | // If the result is less than zero, let error be yes. Otherwise, let density 304 | // be the result. 305 | if (floatVal < 0) { 306 | pError = true; 307 | } else { 308 | d = floatVal; 309 | } 310 | } 311 | // If the descriptor consists of a valid non-negative integer followed by 312 | // a U+0068 LATIN SMALL LETTER H character 313 | else if (regexNonNegativeInteger.test(value) && lastChar === "h") { 314 | // If height and density are not both absent, then let error be yes. 315 | if (h || d) { 316 | pError = true; 317 | } 318 | 319 | // Apply the rules for parsing non-negative integers to the descriptor. 320 | // If the result is zero, let error be yes. Otherwise, let future-compat-h 321 | // be the result. 322 | if (intVal === 0) { 323 | pError = true; 324 | } else { 325 | h = intVal; 326 | } 327 | 328 | // Anything else, Let error be yes. 329 | } else { 330 | pError = true; 331 | } 332 | } 333 | 334 | // 15. If error is still no, then append a new image source to candidates whose 335 | // URL is url, associated with a width width if not absent and a pixel 336 | // density density if not absent. Otherwise, there is a parse error. 337 | if (!pError) { 338 | candidate.source = { value: url, startOffset }; 339 | 340 | if (w) { 341 | candidate.width = { value: w }; 342 | } 343 | 344 | if (d) { 345 | candidate.density = { value: d }; 346 | } 347 | 348 | if (h) { 349 | candidate.height = { value: h }; 350 | } 351 | 352 | candidates.push(candidate); 353 | } else { 354 | throw new Error( 355 | `Invalid srcset descriptor found in "${input}" at "${desc}".` 356 | ); 357 | } 358 | } 359 | } 360 | 361 | export default parseSrcset; -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import test from "node:test"; 2 | import assert from "node:assert/strict"; 3 | import he from 'he'; 4 | import parseSrcset from './index.js'; 5 | 6 | // HTML Entities are much easier to troubleshoot in console. 7 | const encodeHtmlEntities = text => he.encode(text, {useNamedReferences: true}); 8 | const decodeHtmlEntities = text => he.decode(text); 9 | 10 | 11 | // Adapted from the W3C srcset conformance checker at: 12 | // http://w3c-test.org/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html 13 | const w3Ctests = [ 14 | { 15 | groupName: "Splitting Loop", 16 | testArray: [ 17 | {srcset: '', expect: '', desc: 'empty string', expectFailure: true}, 18 | {srcset: ',' , expect: '', desc: 'single comma', expectFailure: true}, 19 | {srcset: ',,,', expect: '', desc: 'three commas', expectFailure: true}, 20 | {srcset: ' data:,a 1x ', expect: 'data:,a', desc: 'tabs'}, 21 | {srcset: ' data:,a 1x ', expect: 'data:,a', desc: 'line feeds'}, 22 | {srcset: ' data:,a 1x ', expect: ' data:,a 1x ', desc: 'line tab'}, 23 | {srcset: ' data:,a 1x ', expect: 'data:,a', desc: 'form feed U+000C'}, 24 | {srcset: ' data:,a 1x ', expect: 'data:,a', desc: 'carriage return U+000D'}, 25 | {srcset: 'data:,a1x', expect: 'data:,a1x', desc: 'shift out U+000E'}, 26 | {srcset: 'data:,a1x', expect: 'data:,a1x', desc: 'shift in U+000F' }, 27 | {srcset: 'data:,a1x', expect: 'data:,a1x', desc: 'data link escape U+0010' }, 28 | {srcset: 'data:,a', expect: 'data:,a', desc:'plain url'}, 29 | {srcset: 'data:,a ', expect: 'data:,a', desc:'trailing space'}, 30 | {srcset: 'data:,a ,', expect: 'data:,a', desc:'trailing space and comma'}, 31 | {srcset: 'data:,a,', expect: 'data:,a', desc:'trailing comma'}, 32 | {srcset: 'data:,a, ', expect: 'data:,a', desc:'trailing comma and space'}, 33 | {srcset: 'data:,a,,,', expect: 'data:,a', desc:'trailing three commas'}, 34 | {srcset: 'data:,a,, , ', expect: 'data:,a', desc:'trailing two commas space comma space'}, 35 | {srcset: ' data:,a', expect: 'data:,a', desc:'leading space'}, 36 | {srcset: ',,,data:,a', expect: 'data:,a', desc:'leading three commas'}, 37 | {srcset: ' , ,,data:,a', expect: 'data:,a', desc:'leading space comma space comma comma'}, 38 | {srcset: ' data:,a', expect: ' data:,a', desc:'leading non-breaking space'}, 39 | {srcset: 'data:,a ', expect: 'data:,a ', desc:'trailing non-breaking space'} 40 | ] 41 | }, 42 | 43 | { 44 | groupName: "Descriptor Tokenizer", 45 | testArray: [ 46 | {srcset: 'data:,a 1x', expect: 'data:,a', desc: 'plain url with descriptor'}, 47 | {srcset: 'data:,a 1x ', expect: 'data:,a', desc: 'trailing space'}, 48 | {srcset: 'data:,a 1x,', expect: 'data:,a', desc: 'trailing comma'}, 49 | {srcset: 'data:,a ( , data:,b 1x, ), data:,c', expect: 'data:,c', desc: 'irregular parens 1', expectFailure: true}, 50 | {srcset: 'data:,a ((( , data:,b 1x, ), data:,c', expect: 'data:,c', desc: 'irregular parens 2', expectFailure: true}, 51 | {srcset: 'data:,a [ , data:,b 1x, ], data:,c', expect: 'data:,b', desc: 'brackets', expectFailure: true}, 52 | {srcset: 'data:,a { , data:,b 1x, }, data:,c', expect: 'data:,b', desc: 'braces', expectFailure: true}, 53 | {srcset: 'data:,a " , data:,b 1x, ", data:,c', expect: 'data:,b', desc: 'double quotes', expectFailure: true}, 54 | {srcset: 'data:,a \\,data:;\\,b, data:,c', expect: 'data:;\\,b', desc: 'backslashes', expectFailure: true}, 55 | {srcset: 'data:,a, data:,b (', expect: 'data:,a', desc: 'trailing unclosed paren', expectFailure: true}, 56 | {srcset: 'data:,a, data:,b ( ', expect: 'data:,a', desc: 'unclosed paren space', expectFailure: true}, 57 | {srcset: 'data:,a, data:,b (,', expect: 'data:,a', desc: 'unclosed paren comma', expectFailure: true}, 58 | {srcset: 'data:,a, data:,b (x', expect: 'data:,a', desc: 'unclosed paren x', expectFailure: true}, 59 | {srcset: 'data:,a, data:,b ()', expect: 'data:,a', desc: 'parens, no descriptor', expectFailure: true}, 60 | {srcset: 'data:,a (, data:,b', expect: '', desc: 'unclosed paren', expectFailure: true}, 61 | {srcset: 'data:,a /*, data:,b, data:,c */', expect: 'data:,b', desc: 'block comments', expectFailure: true}, 62 | {srcset: 'data:,a //, data:,b', expect: 'data:,b', desc: 'double slash like a comment', expectFailure: true} 63 | ] 64 | }, 65 | 66 | { groupName: "Descriptor Parser", 67 | testArray : [ 68 | {srcset: 'data:,a foo', expect: '', desc: 'trailing foo', expectFailure: true}, 69 | {srcset: 'data:,a foo foo', expect: '', desc: 'trailing foo foo', expectFailure: true}, 70 | {srcset: 'data:,a foo 1x', expect: '', desc: 'trailing foo 1x', expectFailure: true}, 71 | {srcset: 'data:,a foo 1x foo', expect: '', desc: 'trailing 1x foo', expectFailure: true}, 72 | {srcset: 'data:,a foo 1w', expect: '', desc: 'trailing foo 1w', expectFailure: true}, 73 | {srcset: 'data:,a foo 1w foo', expect: '', desc: 'trailing foo 1w foo', expectFailure: true}, 74 | {srcset: 'data:,a 1x 1x', expect: '', desc: 'two density descriptors', expectFailure: true}, 75 | {srcset: 'data:,a 1w 1w', expect: '', desc: 'two width descriptors', expectFailure: true}, 76 | {srcset: 'data:,a 1h 1h', expect: '', desc: 'two height descriptors', expectFailure: true}, 77 | {srcset: 'data:,a 1w 1x', expect: '', desc: 'width then density', expectFailure: true}, 78 | {srcset: 'data:,a 1x 1w', expect: '', desc: 'density then width', expectFailure: true}, 79 | {srcset: 'data:,a 1w 1h', expect: 'data:,a', desc: 'width then height'}, 80 | {srcset: 'data:,a 1h 1w', expect: 'data:,a', desc: 'height then width'}, 81 | {srcset: 'data:,a 1h 1x', expect: '', desc: 'height then density', expectFailure: true}, 82 | {srcset: 'data:,a 1h 1w 1x', expect: '', desc: 'height then width then density', expectFailure: true}, 83 | {srcset: 'data:,a 1x 1w 1h', expect: '', desc: 'density then width then height', expectFailure: true}, 84 | {srcset: 'data:,a 1h foo', expect: '', desc: 'trailing 1h foo', expectFailure: true}, 85 | {srcset: 'data:,a foo 1h', expect: '', desc: 'trailing foo 1h', expectFailure: true}, 86 | {srcset: 'data:,a 0w', expect: '', desc: 'zero width', expectFailure: true}, 87 | {srcset: 'data:,a -1w', expect: '', desc: 'negative width', expectFailure: true}, 88 | {srcset: 'data:,a 1w -1w', expect: '', desc: 'positive width, negative width', expectFailure: true}, 89 | {srcset: 'data:,a 1.0w', expect: '', desc: 'floating point width', expectFailure: true}, 90 | {srcset: 'data:,a 1w 1.0w', expect: '', desc: 'integer width, floating point width', expectFailure: true}, 91 | {srcset: 'data:,a 1e0w', expect: '', desc: 'exponent width', expectFailure: true}, 92 | {srcset: 'data:,a 1w 1e0w', expect: '', desc: 'integer width, exponent width', expectFailure: true}, 93 | {srcset: 'data:,a 1www', expect: '', desc: '1www', expectFailure: true}, 94 | {srcset: 'data:,a 1w 1www', expect: '', desc: '1w 1www', expectFailure: true}, 95 | {srcset: 'data:,a 1w +1w', expect: '', desc: '1w +1w', expectFailure: true}, 96 | {srcset: 'data:,a 1W', expect: '', desc: 'capital W descriptor', expectFailure: true}, 97 | {srcset: 'data:,a 1w 1W', expect: '', desc: 'lowercase w, capital W descriptors', expectFailure: true}, 98 | {srcset: 'data:,a Infinityw', expect: '', desc: 'Infinityw', expectFailure: true}, 99 | {srcset: 'data:,a 1w Infinityw', expect: '', desc: '1w Infinityw', expectFailure: true}, 100 | {srcset: 'data:,a NaNw', expect: '', desc: 'Nanw', expectFailure: true}, 101 | {srcset: 'data:,a 1w NaNw', expect: '', desc: '1w Nanw', expectFailure: true}, 102 | {srcset: 'data:,a 0x1w', expect: '', desc: 'ox1w', expectFailure: true}, 103 | {srcset: 'data:,a 1w', expect: '', desc: 'trailing U+0001', expectFailure: true}, 104 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+00A0', expectFailure: true}, 105 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+1680', expectFailure: true}, 106 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2000', expectFailure: true}, 107 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2001', expectFailure: true}, 108 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2002', expectFailure: true}, 109 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2003', expectFailure: true}, 110 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2004', expectFailure: true}, 111 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2005', expectFailure: true}, 112 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2006', expectFailure: true}, 113 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2007', expectFailure: true}, 114 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2008', expectFailure: true}, 115 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+2009', expectFailure: true}, 116 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+200A', expectFailure: true}, 117 | {srcset: 'data:,a 1‌w', expect: '', desc: 'trailing U+200C', expectFailure: true}, 118 | {srcset: 'data:,a 1‍w', expect: '', desc: 'trailing U+200D', expectFailure: true}, 119 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+202F', expectFailure: true}, 120 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+205F', expectFailure: true}, 121 | {srcset: 'data:,a 1 w', expect: '', desc: 'trailing U+3000', expectFailure: true}, 122 | {srcset: 'data:,a 1w', expect: '', desc: 'trailing U+FEFF', expectFailure: true}, 123 | {srcset: 'data:,a 1w' , expect: '', desc: 'leading U+0001', expectFailure: true}, 124 | // {srcset: 'data:,a  1w' , expect: '', desc: 'leading U+00A0 width'}, 125 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+1680', expectFailure: true}, 126 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2000', expectFailure: true}, 127 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2001', expectFailure: true}, 128 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2002', expectFailure: true}, 129 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2003', expectFailure: true}, 130 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2004', expectFailure: true}, 131 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2005', expectFailure: true}, 132 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2006', expectFailure: true}, 133 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2007', expectFailure: true}, 134 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2008', expectFailure: true}, 135 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+2009', expectFailure: true}, 136 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+200A', expectFailure: true}, 137 | {srcset: 'data:,a ‌1w', expect: '', desc: 'leading U+200C', expectFailure: true}, 138 | {srcset: 'data:,a ‍1w', expect: '', desc: 'leading U+200D', expectFailure: true}, 139 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+202F', expectFailure: true}, 140 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+205F', expectFailure: true}, 141 | {srcset: 'data:,a  1w', expect: '', desc: 'leading U+3000', expectFailure: true}, 142 | {srcset: 'data:,a 1w', expect: '', desc: 'leading U+FEFF', expectFailure: true}, 143 | {srcset: 'data:,a 0x', expect: 'data:,a', desc: 'zero density'}, 144 | {srcset: 'data:,a -0x' , expect: 'data:,a', desc: 'negative zero density'}, 145 | {srcset: 'data:,a 1x -0x', expect: '', desc: '1x -0x', expectFailure: true}, 146 | {srcset: 'data:,a -1x', expect: '', desc: '-1x', expectFailure: true}, 147 | {srcset: 'data:,a 1x -1x', expect: '', desc: '1x -1x', expectFailure: true}, 148 | {srcset: 'data:,a 1e0x', expect: 'data:,a', desc: '1e0x'}, 149 | {srcset: 'data:,a 1E0x', expect: 'data:,a', desc: '1E0x'}, 150 | {srcset: 'data:,a 1e-1x', expect: 'data:,a', desc: '1e-1x'}, 151 | {srcset: 'data:,a 1.5e1x', expect: 'data:,a', desc: '1.5e1x'}, 152 | {srcset: 'data:,a -x', expect: '', desc: 'negative density with no digits', expectFailure: true}, 153 | {srcset: 'data:,a .x', expect: '', desc: 'decimal density with no digits', expectFailure: true}, 154 | {srcset: 'data:,a -.x', expect: '', desc: '-.x', expectFailure: true}, 155 | {srcset: 'data:,a 1.x', expect: '', desc: '1.x', expectFailure: true}, 156 | {srcset: 'data:,a .5x', expect: 'data:,a', desc: 'floating point density descriptor'}, 157 | {srcset: 'data:,a .5e1x', expect: 'data:,a', desc: '.5e1x'}, 158 | {srcset: 'data:,a 1x 1.5e1x', expect: '', desc: '1x 1.5e1x', expectFailure: true}, 159 | {srcset: 'data:,a 1x 1e1.5x', expect: '', desc: '1x 1e1.5x', expectFailure: true}, 160 | {srcset: 'data:,a 1.0x', expect: 'data:,a', desc: '1.0x'}, 161 | {srcset: 'data:,a 1x 1.0x', expect: '', desc: '1x 1.0x', expectFailure: true}, 162 | {srcset: 'data:,a +1x', expect: '', desc: 'no plus sign allowed on floating point number', expectFailure: true}, 163 | {srcset: 'data:,a 1X', expect: '', desc: 'Capital X descriptor', expectFailure: true}, 164 | {srcset: 'data:,a Infinityx', expect: '', desc: 'Infinityx', expectFailure: true}, 165 | {srcset: 'data:,a NaNx', expect: '', desc: 'NaNx', expectFailure: true}, 166 | {srcset: 'data:,a 0x1x', expect: '', desc: '0X1x', expectFailure: true}, 167 | {srcset: 'data:,a 0X1x', expect: '', desc: '1x', expectFailure: true}, 168 | {srcset: 'data:,a 1x', expect: '', desc: 'trailing U+0001', expectFailure: true}, 169 | {srcset: 'data:,a 1 x' , expect: '', desc: 'trailing U+00A0 density', expectFailure: true}, 170 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+1680', expectFailure: true}, 171 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2000', expectFailure: true}, 172 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2001', expectFailure: true}, 173 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2002', expectFailure: true}, 174 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2003', expectFailure: true}, 175 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2004', expectFailure: true}, 176 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2005', expectFailure: true}, 177 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2006', expectFailure: true}, 178 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2007', expectFailure: true}, 179 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2008', expectFailure: true}, 180 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+2009', expectFailure: true}, 181 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+200A', expectFailure: true}, 182 | {srcset: 'data:,a 1‌x', expect: '', desc: 'trailing U+200C', expectFailure: true}, 183 | {srcset: 'data:,a 1‍x', expect: '', desc: 'trailing U+200D', expectFailure: true}, 184 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+202F', expectFailure: true}, 185 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+205F', expectFailure: true}, 186 | {srcset: 'data:,a 1 x', expect: '', desc: 'trailing U+3000', expectFailure: true}, 187 | {srcset: 'data:,a 1x', expect: '', desc: 'trailing U+FEFF', expectFailure: true}, 188 | {srcset: 'data:,a 1x' , expect: '', desc: 'leading U+0001', expectFailure: true}, 189 | {srcset: 'data:,a  1x' , expect: '', desc: 'leading U+00A0 density', expectFailure: true}, 190 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+1680', expectFailure: true}, 191 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2000', expectFailure: true}, 192 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2001', expectFailure: true}, 193 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2002', expectFailure: true}, 194 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2003', expectFailure: true}, 195 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2004', expectFailure: true}, 196 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2005', expectFailure: true}, 197 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2006', expectFailure: true}, 198 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2007', expectFailure: true}, 199 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2008', expectFailure: true}, 200 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+2009', expectFailure: true}, 201 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+200A', expectFailure: true}, 202 | {srcset: 'data:,a ‌1x', expect: '', desc: 'leading U+200C', expectFailure: true}, 203 | {srcset: 'data:,a ‍1x', expect: '', desc: 'leading U+200D', expectFailure: true}, 204 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+202F', expectFailure: true}, 205 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+205F', expectFailure: true}, 206 | {srcset: 'data:,a  1x', expect: '', desc: 'leading U+3000', expectFailure: true}, 207 | {srcset: 'data:,a 1x', expect: '', desc: 'leading U+FEFF', expectFailure: true}, 208 | {srcset: 'data:,a 1w 0h', expect: '', desc: '1w 0h', expectFailure: true}, 209 | {srcset: 'data:,a 1w -1h', expect: '', desc: '1w -1h', expectFailure: true}, 210 | {srcset: 'data:,a 1w 1.0h', expect: '', desc: '1w 1.0h', expectFailure: true}, 211 | {srcset: 'data:,a 1w 1e0h', expect: '', desc: '1w 1e0h', expectFailure: true}, 212 | {srcset: 'data:,a 1w 1hhh', expect: '', desc: '1w 1hhh', expectFailure: true}, 213 | {srcset: 'data:,a 1w 1H', expect: '', desc: '1w 1H', expectFailure: true}, 214 | {srcset: 'data:,a 1w Infinityh', expect: '', desc: '1w Infinityh', expectFailure: true}, 215 | {srcset: 'data:,a 1w NaNh', expect: '', desc: '1w NaNh', expectFailure: true}, 216 | {srcset: 'data:,a 0x1h', expect: '', desc: '0x1h', expectFailure: true}, 217 | {srcset: 'data:,a 0X1h', expect: '', desc: '0X1h', expectFailure: true}, 218 | {srcset: 'data:,a 1w 1h', expect: '', desc: 'trailing U+0001', expectFailure: true}, 219 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+00A0', expectFailure: true}, 220 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+1680', expectFailure: true}, 221 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2000', expectFailure: true}, 222 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2001', expectFailure: true}, 223 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2002', expectFailure: true}, 224 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2003', expectFailure: true}, 225 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2004', expectFailure: true}, 226 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2005', expectFailure: true}, 227 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2006', expectFailure: true}, 228 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2007', expectFailure: true}, 229 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2008', expectFailure: true}, 230 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+2009', expectFailure: true}, 231 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+200A', expectFailure: true}, 232 | {srcset: 'data:,a 1w 1‌h', expect: '', desc: 'trailing U+200C', expectFailure: true}, 233 | {srcset: 'data:,a 1w 1‍h', expect: '', desc: 'trailing U+200D', expectFailure: true}, 234 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+202F', expectFailure: true}, 235 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+205F', expectFailure: true}, 236 | {srcset: 'data:,a 1w 1 h', expect: '', desc: 'trailing U+3000', expectFailure: true}, 237 | {srcset: 'data:,a 1w 1h', expect: '', desc: 'trailing U+FEFF', expectFailure: true}, 238 | {srcset: 'data:,a 1w 1h', expect: '', desc: 'leading U+0001', expectFailure: true}, 239 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+00A0', expectFailure: true}, 240 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+1680', expectFailure: true}, 241 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2000', expectFailure: true}, 242 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2001', expectFailure: true}, 243 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2002', expectFailure: true}, 244 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2003', expectFailure: true}, 245 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2004', expectFailure: true}, 246 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2005', expectFailure: true}, 247 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2006', expectFailure: true}, 248 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2007', expectFailure: true}, 249 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2008', expectFailure: true}, 250 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+2009', expectFailure: true}, 251 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+200A', expectFailure: true}, 252 | {srcset: 'data:,a 1w ‌1h', expect: '', desc: 'leading U+200C', expectFailure: true}, 253 | {srcset: 'data:,a 1w ‍1h', expect: '', desc: 'leading U+200D', expectFailure: true}, 254 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+202F', expectFailure: true}, 255 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+205F', expectFailure: true}, 256 | {srcset: 'data:,a 1w  1h', expect: '', desc: 'leading U+3000', expectFailure: true}, 257 | {srcset: 'data:,a 1w 1h', expect: '', desc: 'leading U+FEFF', expectFailure: true} 258 | ] 259 | } 260 | ]; 261 | 262 | function runTest(testCase) { 263 | return test(`${testCase.desc} (${testCase.srcset})`, () => { 264 | const origAttr = testCase.srcset; 265 | const attrDecoded = decodeHtmlEntities(origAttr); 266 | const parsed = parseSrcset(attrDecoded); 267 | 268 | const firstCandidate = parsed[0]; 269 | 270 | let url = ""; 271 | let encodedUrl = ""; 272 | 273 | if (firstCandidate) { 274 | url = firstCandidate.source.value; 275 | } 276 | 277 | // Must re-encode url prior to comparison with expected string. 278 | if (url) { 279 | encodedUrl = encodeHtmlEntities(url); 280 | } 281 | 282 | assert.strictEqual(encodedUrl, testCase.expect, "passed" ); 283 | }); 284 | } 285 | 286 | for (const {groupName, testArray} of w3Ctests) { 287 | // Group Tests 288 | test(groupName, async () => { 289 | for (const testCase of testArray) { 290 | if (testCase.expectFailure) { 291 | await test(testCase.desc, () => { 292 | assert.throws(() => { 293 | const origAttr = testCase.srcset; 294 | const attrDecoded = decodeHtmlEntities(origAttr); 295 | parseSrcset(attrDecoded); 296 | }) 297 | }) 298 | } else { 299 | await runTest(testCase); 300 | } 301 | } 302 | }); 303 | } 304 | 305 | // tdd.test('First Test', function () { 306 | // var parsed = parseSrcset('data:,a 1x'); 307 | // var url = parsed[0].url; 308 | // 309 | // console.log("parsed: ", parsed); 310 | // console.log("url: ", url); 311 | // 312 | // assert.strictEqual(parsed, parsed, 'should be'); 313 | // 314 | // // assert.strictEqual(url, 'data:,a', 'should be'); 315 | // }); 316 | 317 | // assert.strictEqual(parseSrcset('data:,a 1x')[0], 'data:,a', 'plain url with descriptor'); 318 | 319 | // tdd.test('Second Test', function () { 320 | // assert.strictEqual(5, 5, '5 is itself, right?'); 321 | // }); 322 | --------------------------------------------------------------------------------