Summary
format-css strips the outer quotes from url('data:...') values even when the
inner content contains " or ' characters. The resulting unquoted url() is
invalid CSS because bare " and ' are not allowed inside an unquoted URL token
(CSS spec §4.3.6). Downstream parsers (PostCSS, stylelint) then report
"Unclosed string".
Reproduction
import { format } from '@projectwallace/format-css'
// Input: outer single quotes protect inner double quotes
const input = `.a { background: url('data:image/svg+xml,%3Csvg fill="red"%3E%3C/svg%3E'); }`
console.log(format(input))
Output (current — invalid CSS):
.a {
background: url(data:image/svg+xml,%3Csvg fill="red"%3E%3C/svg%3E);
}
The outer single quotes are removed. The inner " characters are now bare inside
an unquoted url(), which is illegal. PostCSS/stylelint fails to parse this with:
Unclosed string (CssSyntaxError)
Expected output (valid CSS):
.a {
background: url("data:image/svg+xml,%3Csvg fill=\"red\"%3E%3C/svg%3E");
}
The value should stay quoted (wrapped in double quotes) because it contains
characters that are not safe in an unquoted URL.
Real-world trigger
This surfaces with Gravity Forms stylesheets, which embed SVG icons as custom
properties using single-quoted url() values where SVG attributes use double
quotes:
#gform_wrapper_3[data-form-index="0"].gform-theme,
[data-parent-form="3_0"] {
--gf-icon-ctrl-number: url('data:image/svg+xml,%3Csvg width=\'8\' height=\'14\' fill=\'none\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath fill=\'rgba(17, 35, 55, 0.65)\'/%3E%3C/svg%3E');
}
After formatting, the outer quotes are stripped and the inner single quotes
become bare, also triggering the same parse error.
Root cause
In dist/index.js, the url-printing branch unconditionally unquotes data: URLs:
if (/^['"]?data:/i.test(value)) parts.push(unquote(value));
else parts.push(print_string(value));
Suggested fix
Only unquote a data: URL value when it is safe to do so — i.e. the unquoted
value contains neither " nor '. When inner quotes are present, choose the
outer delimiter that does not conflict:
if (/^['"]?data:/i.test(value)) {
const unquoted = unquote(value);
if (!unquoted.includes('"') && !unquoted.includes("'")) {
// Safe to leave unquoted
parts.push(unquoted);
} else if (!unquoted.includes('"')) {
// Inner single quotes only — wrap in double quotes
parts.push('"' + unquoted + '"');
} else if (!unquoted.includes("'")) {
// Inner double quotes only — wrap in single quotes
parts.push("'" + unquoted + "'");
} else {
// Both quote types — URL-encode the double quotes and wrap in double quotes
parts.push('"' + unquoted.replaceAll('"', '%22') + '"');
}
}
Version
@projectwallace/format-css 3.1.3
Summary
format-cssstrips the outer quotes fromurl('data:...')values even when theinner content contains
"or'characters. The resulting unquotedurl()isinvalid CSS because bare
"and'are not allowed inside an unquoted URL token(CSS spec §4.3.6). Downstream parsers (PostCSS, stylelint) then report
"Unclosed string".
Reproduction
Output (current — invalid CSS):
The outer single quotes are removed. The inner
"characters are now bare insidean unquoted
url(), which is illegal. PostCSS/stylelint fails to parse this with:Expected output (valid CSS):
The value should stay quoted (wrapped in double quotes) because it contains
characters that are not safe in an unquoted URL.
Real-world trigger
This surfaces with Gravity Forms stylesheets, which embed SVG icons as custom
properties using single-quoted
url()values where SVG attributes use doublequotes:
After formatting, the outer quotes are stripped and the inner single quotes
become bare, also triggering the same parse error.
Root cause
In
dist/index.js, the url-printing branch unconditionally unquotesdata:URLs:Suggested fix
Only unquote a
data:URL value when it is safe to do so — i.e. the unquotedvalue contains neither
"nor'. When inner quotes are present, choose theouter delimiter that does not conflict:
Version
@projectwallace/format-css3.1.3