Skip to content

Commit b119d02

Browse files
fix: handling unquoted syntax url with escaped characters (#1010)
1 parent 880344b commit b119d02

File tree

8 files changed

+130
-14
lines changed

8 files changed

+130
-14
lines changed

src/plugins/postcss-url-parser.js

+25-11
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ function getNodeFromUrlFunc(node) {
1111
return node.nodes && node.nodes[0];
1212
}
1313

14-
function getUrlFromUrlFunc(node) {
15-
return node.nodes.length !== 0 && node.nodes[0].type === 'string'
16-
? node.nodes[0].value
17-
: valueParser.stringify(node.nodes);
18-
}
19-
2014
function walkUrls(parsed, callback) {
2115
parsed.walk((node) => {
2216
if (node.type !== 'function') {
2317
return;
2418
}
2519

2620
if (isUrlFunc.test(node.value)) {
27-
callback(getNodeFromUrlFunc(node), getUrlFromUrlFunc(node), false);
21+
const isStringNode =
22+
node.nodes.length !== 0 && node.nodes[0].type === 'string';
23+
const url = isStringNode
24+
? node.nodes[0].value
25+
: valueParser.stringify(node.nodes);
26+
27+
callback(getNodeFromUrlFunc(node), url, false, isStringNode);
2828

2929
// Do not traverse inside `url`
3030
// eslint-disable-next-line consistent-return
@@ -34,11 +34,17 @@ function walkUrls(parsed, callback) {
3434
if (isImageSetFunc.test(node.value)) {
3535
node.nodes.forEach((nNode) => {
3636
if (nNode.type === 'function' && isUrlFunc.test(nNode.value)) {
37-
callback(getNodeFromUrlFunc(nNode), getUrlFromUrlFunc(nNode), false);
37+
const isStringNode =
38+
nNode.nodes.length !== 0 && nNode.nodes[0].type === 'string';
39+
const url = isStringNode
40+
? nNode.nodes[0].value
41+
: valueParser.stringify(nNode.nodes);
42+
43+
callback(getNodeFromUrlFunc(nNode), url, false, isStringNode);
3844
}
3945

4046
if (nNode.type === 'string') {
41-
callback(nNode, nNode.value, true);
47+
callback(nNode, nNode.value, true, true);
4248
}
4349
});
4450

@@ -57,7 +63,7 @@ function getUrlsFromValue(value, result, filter, decl) {
5763
const parsed = valueParser(value);
5864
const urls = [];
5965

60-
walkUrls(parsed, (node, url, needQuotes) => {
66+
walkUrls(parsed, (node, url, needQuotes, isStringNode) => {
6167
if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
6268
result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, {
6369
node: decl,
@@ -70,12 +76,20 @@ function getUrlsFromValue(value, result, filter, decl) {
7076
return;
7177
}
7278

73-
const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
79+
const splittedUrl = url.split(/(\?)?#/);
80+
let [normalizedUrl] = splittedUrl;
81+
const [, singleQuery, hashValue] = splittedUrl;
7482
const hash =
7583
singleQuery || hashValue
7684
? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}`
7785
: '';
7886

87+
// Remove extra escaping requirements for `require`
88+
// See https://drafts.csswg.org/css-values-3/#urls
89+
if (!isStringNode && /\\["'() \t\n]/.test(normalizedUrl)) {
90+
normalizedUrl = normalizedUrl.replace(/\\(["'() \t\n])/g, '$1');
91+
}
92+
7993
urls.push({ node, url: normalizedUrl, hash, needQuotes });
8094
});
8195

test/__snapshots__/url-option.test.js.snap

+82-3
Large diffs are not rendered by default.

test/fixtures/url/img'''img.png

76.3 KB
Loading

test/fixtures/url/img'() img.png

76.3 KB
Loading

test/fixtures/url/img'img.png

76.3 KB
Loading

test/fixtures/url/img(img.png

76.3 KB
Loading

test/fixtures/url/img)img.png

76.3 KB
Loading

test/fixtures/url/url.css

+23
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,26 @@ a {
268268

269269
background-image: image-set(url("./img1x.png") 1x, "./img2x.png" 2x);
270270
}
271+
272+
.class {
273+
/* Not allowed on windows */
274+
/* background: url(./img\"img.png); */
275+
background: url(./img\'img.png);
276+
background: url(./img\'\'\'img.png);
277+
background: url(./img\(img.png);
278+
background: url(./img\)img.png);
279+
background: url(./img\ img.png);
280+
background: url(./img\'\(\)\ img.png);
281+
282+
background-image: image-set(
283+
/* Not allowed on windows */
284+
/* url(./img\"img.png) 1x, */
285+
url(./img\'\'\'img.png) 2x,
286+
url(./img\'img.png) 3x,
287+
url(./img\(img.png) 4x,
288+
url(./img\)img.png) 5x,
289+
url(./img\ img.png) 6x,
290+
url(./img\'\(\)\ img.png) 7x
291+
);
292+
}
293+

0 commit comments

Comments
 (0)