Skip to content

Commit 33adb04

Browse files
committed
fix: parsing resource
1 parent 53876b5 commit 33adb04

File tree

2 files changed

+39
-35
lines changed

2 files changed

+39
-35
lines changed

lib/CSSStyleDeclaration.test.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ describe('CSSStyleDeclaration', () => {
9696
var style = new CSSStyleDeclaration();
9797
style.background = 'blue url(http://www.example.com/some_img.jpg)';
9898
expect(style.backgroundColor).toEqual('blue');
99-
expect(style.backgroundImage).toEqual('url(http://www.example.com/some_img.jpg)');
100-
expect(style.background).toEqual('blue url(http://www.example.com/some_img.jpg)');
99+
// Jest escape quotes but the output value is not escaped
100+
expect(style.backgroundImage).toEqual('url("http://www.example.com/some_img.jpg")');
101+
expect(style.background).toEqual('blue url("http://www.example.com/some_img.jpg")');
101102
style.border = '0 solid black';
102103
expect(style.borderWidth).toEqual('0px');
103104
expect(style.borderStyle).toEqual('solid');
@@ -209,8 +210,9 @@ describe('CSSStyleDeclaration', () => {
209210
var style = new CSSStyleDeclaration();
210211
style.background = 'rgb(0, 0, 0) url(/something/somewhere.jpg)';
211212
expect(style.backgroundColor).toEqual('rgb(0, 0, 0)');
212-
expect(style.backgroundImage).toEqual('url(/something/somewhere.jpg)');
213-
expect(style.cssText).toEqual('background: rgb(0, 0, 0) url(/something/somewhere.jpg);');
213+
// Jest escape quotes but the output value is not escaped
214+
expect(style.backgroundImage).toEqual('url("/something/somewhere.jpg")');
215+
expect(style.cssText).toEqual('background: rgb(0, 0, 0) url("/something/somewhere.jpg");');
214216
style = new CSSStyleDeclaration();
215217
style.border = ' 1px solid black ';
216218
expect(style.border).toEqual('1px solid black');
@@ -431,11 +433,12 @@ describe('CSSStyleDeclaration', () => {
431433
test('url parsing works with quotes', () => {
432434
var style = new CSSStyleDeclaration();
433435
style.backgroundImage = 'url(http://some/url/here1.png)';
434-
expect(style.backgroundImage).toEqual('url(http://some/url/here1.png)');
436+
// Jest escape quotes but the output value is not escaped
437+
expect(style.backgroundImage).toEqual('url("http://some/url/here1.png")');
435438
style.backgroundImage = "url('http://some/url/here2.png')";
436-
expect(style.backgroundImage).toEqual('url(http://some/url/here2.png)');
439+
expect(style.backgroundImage).toEqual('url("http://some/url/here2.png")');
437440
style.backgroundImage = 'url("http://some/url/here3.png")';
438-
expect(style.backgroundImage).toEqual('url(http://some/url/here3.png)');
441+
expect(style.backgroundImage).toEqual('url("http://some/url/here3.png")');
439442
});
440443

441444
test('setting 0 to a padding or margin works', () => {

lib/parsers.js

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@ const ident = `(-?([a-z]|${escape})(\\w|${escape})*|--(\\w|${escape})*)`;
6464
const integer = '[-+]?\\d+';
6565
const number = `((${integer})(\\.\\d+)?|[-+]?(\\.\\d+))(e[-+]?${integer})?`;
6666
const percentage = `(${number})(%)`;
67+
const escapeRegEx = new RegExp(`${escape}`, 'i');
6768
const identRegEx = new RegExp(`^${ident}$`, 'i');
6869
const numberRegEx = new RegExp(`^${number}$`);
6970
const percentageRegEx = new RegExp(`^${percentage}$`);
7071
const stringRegEx = /^("[^"]*"|'[^']*')$/;
71-
const urlRegEx = /^url\(\s*([^)]*)\s*\)$/;
72+
const urlRegEx = new RegExp(`^url\\(${ws}([^"'() \\t${newline}\\\\]|${escape})+${ws}\\)$`, 'i');
7273
const whitespaceRegEx = new RegExp(`^${whitespace}$`);
7374
const trailingWhitespaceRegEx = new RegExp(`.*${whitespace}$`);
7475

@@ -105,6 +106,7 @@ const gradientRegEx = new RegExp(
105106
);
106107
const lengthRegEx = new RegExp(`^${length}$`, 'i');
107108
const numericRegEx = new RegExp(`^(${number})(%|${ident})?$`, 'i');
109+
const resourceRegEx = new RegExp(`^(src|url)\\(${ws}(.*)${ws}\\)$`, 'i');
108110
const timeRegEx = new RegExp(`^(${number})(m?s)$`, 'i');
109111

110112
/**
@@ -582,47 +584,46 @@ exports.parseDashedIdentifier = function parseDashedIdentifier(val) {
582584
* TODO: <image-set()>, <cross-fade()>, <element()>.
583585
*/
584586
exports.parseImage = function parseImage(val) {
585-
return exports.parseUrl(val) || exports.parseGradient(val);
587+
return exports.parseResource(val) || exports.parseGradient(val);
586588
};
587589

588590
/**
589591
* https://drafts.csswg.org/css-values-4/#urls
590592
* https://drafts.csswg.org/cssom/#ref-for-url-value
593+
*
594+
* url(<url>)
595+
* url(<string> <url-modifier>?)
596+
* src(<string> <url-modifier>?)
597+
* src(<custom-var> <url-modifier>?)
598+
*
599+
* TODO: handle <url-modifier> (<ident> or <fn>).
591600
*/
592-
exports.parseUrl = function parseUrl(val) {
601+
exports.parseResource = function parseResource(val) {
593602
if (val === '') {
594603
return val;
595604
}
596-
var res = urlRegEx.exec(val);
597-
// does it match the regex?
605+
const res = resourceRegEx.exec(val);
598606
if (res) {
599-
var str = res[1];
600-
// if it starts with single or double quotes, does it end with the same?
601-
if ((str[0] === '"' || str[0] === "'") && str[0] !== str[str.length - 1]) {
607+
let [, type, urlOrString] = res;
608+
type = type.toLowerCase();
609+
urlOrString = urlOrString.replace(escapeRegEx, m => m.trim());
610+
if (urlOrString.replace(/"|'/g, '').trim() === '') {
602611
return undefined;
603612
}
604-
if (str[0] === '"' || str[0] === "'") {
605-
str = str.substr(1, str.length - 2);
606-
}
607-
608-
var i;
609-
for (i = 0; i < str.length; i++) {
610-
switch (str[i]) {
611-
case '(':
612-
case ')':
613-
case ' ':
614-
case '\t':
615-
case '\n':
616-
case "'":
617-
case '"':
618-
return undefined;
619-
case '\\':
620-
i++;
621-
break;
613+
const variable = exports.parseCustomVariable(urlOrString);
614+
if (variable) {
615+
if (type === 'src') {
616+
return `src(${variable})`;
622617
}
618+
return undefined;
619+
}
620+
const string = exports.parseString(urlOrString);
621+
if (string) {
622+
return `${type}(${string})`;
623+
}
624+
if (type === 'url' && urlRegEx.test(`url(${urlOrString})`)) {
625+
return `url("${urlOrString}")`;
623626
}
624-
625-
return 'url(' + str + ')';
626627
}
627628
return exports.parseCustomVariable(val);
628629
};

0 commit comments

Comments
 (0)