Skip to content

Commit 362359e

Browse files
authored
Improve parsing of srcset according to whatwg spec (#74)
* Improve parsing of srcset according to whatwg spec; e.g. srcset="http://example.com/size400,300/img.jpg 640w" * Trim/normalise the output in order to conform to prior version; solely to keep tests happy * Add test case for embedded commas in a srcset url as well as support for future possible parenthesis in descriptor string * Drop 'future proof' test as it causes an error message in test output
1 parent 7850a75 commit 362359e

File tree

3 files changed

+69
-21
lines changed

3 files changed

+69
-21
lines changed

src/snapshot.ts

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,32 +110,78 @@ export function absoluteToStylesheet(
110110
);
111111
}
112112

113+
const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/; // Don't use \s, to avoid matching non-breaking space
114+
const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
113115
function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
116+
/*
117+
run absoluteToDoc over every url in the srcset
118+
119+
this is adapted from https://github.com/albell/parse-srcset/
120+
without the parsing of the descriptors (we return these as-is)
121+
parce-srcset is in turn based on
122+
https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute
123+
*/
114124
if (attributeValue.trim() === '') {
115125
return attributeValue;
116126
}
117127

118-
const srcsetValues = attributeValue.split(',');
119-
// srcset attributes is defined as such:
120-
// srcset = "url size,url1 size1"
121-
const resultingSrcsetString = srcsetValues
122-
.map((srcItem) => {
123-
// removing all but middle spaces
124-
const trimmedSrcItem = srcItem.trimLeft().trimRight();
125-
const urlAndSize = trimmedSrcItem.split(' ');
126-
// this means we have both 0:url and 1:size
127-
if (urlAndSize.length === 2) {
128-
const absUrl = absoluteToDoc(doc, urlAndSize[0]);
129-
return `${absUrl} ${urlAndSize[1]}`;
130-
} else if (urlAndSize.length === 1) {
131-
const absUrl = absoluteToDoc(doc, urlAndSize[0]);
132-
return `${absUrl}`;
133-
}
134-
return '';
135-
})
136-
.join(', ');
128+
let pos = 0;
137129

138-
return resultingSrcsetString;
130+
function collectCharacters(regEx: RegExp) {
131+
var chars,
132+
match = regEx.exec(attributeValue.substring(pos));
133+
if (match) {
134+
chars = match[0];
135+
pos += chars.length;
136+
return chars;
137+
}
138+
return '';
139+
}
140+
141+
let output = [];
142+
while (true) {
143+
collectCharacters(SRCSET_COMMAS_OR_SPACES);
144+
if (pos >= attributeValue.length) {
145+
break;
146+
}
147+
// don't split on commas within urls
148+
let url = collectCharacters(SRCSET_NOT_SPACES);
149+
if (url.slice(-1) === ',') {
150+
// aside: according to spec more than one comma at the end is a parse error, but we ignore that
151+
url = absoluteToDoc(doc, url.substring(0, url.length - 1))
152+
// the trailing comma splits the srcset, so the interpretion is that
153+
// another url will follow, and the descriptor is empty
154+
output.push(url);
155+
} else {
156+
let descriptorsStr = '';
157+
url = absoluteToDoc(doc, url)
158+
let inParens = false;
159+
while (true) {
160+
let c = attributeValue.charAt(pos);
161+
if (c === '') {
162+
output.push((url + descriptorsStr).trim());
163+
break;
164+
} else if (!inParens) {
165+
if (c === ',') {
166+
pos += 1;
167+
output.push((url + descriptorsStr).trim());
168+
break; // parse the next url
169+
} else if (c === '(') {
170+
inParens = true;
171+
}
172+
} else {
173+
// in parenthesis; ignore commas
174+
// (parenthesis may be supported by future additions to spec)
175+
if (c === ')') {
176+
inParens = false;
177+
}
178+
}
179+
descriptorsStr += c;
180+
pos += 1;
181+
}
182+
}
183+
}
184+
return output.join(', ');
139185
}
140186

141187
export function absoluteToDoc(doc: Document, attributeValue: string): string {

test/__snapshots__/integration.ts.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ exports[`[html file]: with-relative-res.html 1`] = `
276276
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"\\" />
277277
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"http://localhost:3030/a.jpg\\" />
278278
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"http://exmple.com/a.jpg\\" />
279-
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"http://localhost:3030/a.jpg 3x, http://localhost:3030/a.jpg 45x, http://localhost:3030/b.png\\" /></body></html>"
279+
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"http://localhost:3030/a.jpg 3x, http://localhost:3030/a.jpg 45x, http://localhost:3030/b.png\\" />
280+
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"http://localhost:3030/300,400/a.jpg 300w, http://localhost:3030/b.png\\" /></body></html>"
280281
`;
281282

282283
exports[`[html file]: with-script.html 1`] = `

test/html/with-relative-res.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
<img src="./a.jpg" alt="" srcset="/a.jpg">
1717
<img src="./a.jpg" alt="" srcset="http://exmple.com/a.jpg ">
1818
<img src="./a.jpg" alt="" srcset="/a.jpg 3x, /a.jpg 45x , /b.png">
19+
<img src="./a.jpg" alt="" srcset="/300,400/a.jpg 300w,b.png">
1920
</body>
2021
</html>

0 commit comments

Comments
 (0)