Skip to content

Commit

Permalink
fix(postcss-svgo): normalize SVG with escaped quote characters (#1200)
Browse files Browse the repository at this point in the history
* fix(postcss-svgo): normalize SVG with escaped quote characters

Signed-off-by: Jakka Prihatna <jprihatna@gmail.com>

* chore(postcss-svgo): add comment on regex pattern for escaped-quotes SVG

Co-authored-by: Ludovico Fischer <43557+ludofischer@users.noreply.github.com>
  • Loading branch information
IronGeek and ludofischer committed Oct 19, 2021
1 parent b44b465 commit 4ef5e41
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .all-contributorsrc
Expand Up @@ -629,6 +629,17 @@
"contributions": [
"code"
]
},
{
"login": "IronGeek",
"name": "Jakka Prihatna",
"avatar_url": "https://avatars.githubusercontent.com/u/1383932?v=4",
"profile": "https://github.com/IronGeek",
"contributions": [
"bug",
"code",
"test"
]
}
],
"repoType": "github",
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Expand Up @@ -89,6 +89,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
</tr>
<tr>
<td align="center"><a href="https://github.com/MapTo0"><img src="https://avatars.githubusercontent.com/u/5821279?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/cssnano/cssnano/commits?author=MapTo0" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/IronGeek"><img src="https://avatars.githubusercontent.com/u/1383932?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jakka Prihatna</b></sub></a><br /><a href="https://github.com/cssnano/cssnano/issues?q=author%3AIronGeek" title="Bug reports">🐛</a> <a href="https://github.com/cssnano/cssnano/commits?author=IronGeek" title="Code">💻</a> <a href="https://github.com/cssnano/cssnano/commits?author=IronGeek" title="Tests">⚠️</a></td>
</tr>
</table>

Expand Down
33 changes: 33 additions & 0 deletions packages/postcss-svgo/src/__tests__/index.js
Expand Up @@ -158,6 +158,39 @@ test(
)
);

test('should not warn on "escaped-quotes" svgs', async () => {
const css =
'h1{background-image:url("data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"400\\" height=\\"400\\" fill-opacity=\\".25\\" ><rect x=\\"200\\" width=\\"200\\" height=\\"200\\" /><rect y=\\"200\\" width=\\"200\\" height=\\"200\\" /></svg>")}';
const result = await postcss(plugin()).process(css, { from: undefined });
expect(result.messages.length).toBe(0);
});

test(
'should not fail on "escaped-quotes" svgs',
processCSS(
'h1{background-image:url("data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"400\\" height=\\"400\\" fill-opacity=\\".25\\" ><rect x=\\"200\\" width=\\"200\\" height=\\"200\\" /><rect y=\\"200\\" width=\\"200\\" height=\\"200\\" /></svg>")}',
'h1{background-image:url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" fill-opacity=".25"><path d="M200 0h200v200H200zM0 200h200v200H0z"/></svg>\')}'
)
);

test(
'should encode "unencoded-escaped-quotes" svgs',
processCSS(
'h1{background:url("data:image/svg+xml;charset=utf-8,<svg xmlns=\\"http://www.w3.org/2000/svg\\"><circle cx=\\"50\\" cy=\\"50\\" r=\\"40\\" fill=\\"#ff0\\"/></svg>")}',
"h1{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='50' cy='50' r='40' fill='%23ff0'/%3E%3C/svg%3E\")}",
{ encode: true }
)
);

test(
'should decode on "encoded-escaped-quotes" svgs',
processCSS(
'h1{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\\"http://www.w3.org/2000/svg\\"%3E%3Ccircle cx=\\"50\\" cy=\\"50\\" r=\\"40\\" fill=\\"%23ff0\\"/%3E%3C/svg%3E")}',
'h1{background:url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="40" fill="%23ff0"/></svg>\')}',
{ encode: false }
)
);

test(
'should skip invalid svg',
processCSS(
Expand Down
11 changes: 11 additions & 0 deletions packages/postcss-svgo/src/index.js
Expand Up @@ -6,6 +6,12 @@ const PLUGIN = 'postcss-svgo';
const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
const dataURIBase64 = /data:image\/svg\+xml;base64,/i;

// the following regex will globally match:
// \b([\w-]+) --> a word (a sequence of one or more [alphanumeric|underscore|dash] characters; followed by
// \s*=\s* --> an equal sign character (=) between optional whitespaces; followed by
// \\"([\S\s]+?)\\" --> any characters (including whitespaces and newlines) between literal escaped quotes (\")
const escapedQuotes = /\b([\w-]+)\s*=\s*\\"([\S\s]+?)\\"/g;

/**
* @param {string} input the SVG string
* @param {boolean} encode whether to encode the result
Expand All @@ -30,6 +36,11 @@ function minifySVG(input, opts) {
isUriEncoded = opts.encode;
}

// normalize all escaped quote characters from svg attributes
// from <svg attr=\"value\"... /> to <svg attr="value"... />
// see: https://github.com/cssnano/cssnano/issues/1194
svg = svg.replace(escapedQuotes, '$1="$2"');

const result = optimize(svg, opts);
if (result.error) {
throw new Error(result.error);
Expand Down

0 comments on commit 4ef5e41

Please sign in to comment.