From a9df915d1d565ba96e8ddcb54e430fddf5dda144 Mon Sep 17 00:00:00 2001 From: Seth Falco Date: Sun, 12 Nov 2023 11:56:39 +0000 Subject: [PATCH] fix: dont trim pre elements (#1796) Includes pre in the array of text elements in _collections.js so that we don't trim whitespace on them, which effects rendering. --- .../03-plugins/convert-one-stop-gradients.mdx | 2 +- docs/03-plugins/merge-paths.mdx | 2 +- lib/parser.js | 2 +- lib/stringifier.js | 2 +- plugins/_collections.js | 24 +++++++++--- plugins/convertOneStopGradients.js | 4 +- plugins/removeAttributesBySelector.js | 2 +- plugins/removeDesc.js | 2 +- plugins/removeTitle.js | 2 +- plugins/reusePaths.js | 2 +- test/svgo/_index.test.js | 15 ++++++++ test/svgo/pre-element-pretty.svg | 37 +++++++++++++++++++ test/svgo/pre-element.svg | 31 ++++++++++++++++ 13 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 test/svgo/pre-element-pretty.svg create mode 100644 test/svgo/pre-element.svg diff --git a/docs/03-plugins/convert-one-stop-gradients.mdx b/docs/03-plugins/convert-one-stop-gradients.mdx index 253823aa5..ea5bb6c05 100644 --- a/docs/03-plugins/convert-one-stop-gradients.mdx +++ b/docs/03-plugins/convert-one-stop-gradients.mdx @@ -8,7 +8,7 @@ Converts the [``](https://developer.mozilla.org/docs/Web/SVG/Ele These nodes contain [``](https://developer.mozilla.org/docs/Web/SVG/Element/stop) elements, which represent various colors to transition between. However, if a gradient only contains a single ``, then it's effecitively a solid fill. -Definitions of the gradients are removed, and the parent [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) node is removed if it has no children after optimization. The `xlink:href` namespace is also removed if there are no remaining elements using this attribute. +Definitions of the gradients are removed, and the parent [``](https://developer.mozilla.org/docs/Web/SVG/Element/defs) node is removed if it has no children after optimization. The `xlink:href` namespace is also removed if there are no remaining elements using this attribute. ## Usage diff --git a/docs/03-plugins/merge-paths.mdx b/docs/03-plugins/merge-paths.mdx index 62247576b..1d078b1d1 100644 --- a/docs/03-plugins/merge-paths.mdx +++ b/docs/03-plugins/merge-paths.mdx @@ -10,7 +10,7 @@ svgo: description: Number of decimal places to round to, using conventional rounding rules. default: null noSpaceAfterFlags: - description: If to omit spaces after flags. Flags are values that can only be 0 or 1 and are used by some path commands, namely A and a. + description: If to omit spaces after flags. Flags are values that can only be 0 or 1 and are used by some path commands, namely A and a. default: false --- diff --git a/lib/parser.js b/lib/parser.js index 8c40eda0e..aeed3f099 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -15,7 +15,7 @@ // @ts-ignore sax will be replaced with something else later const SAX = require('@trysound/sax'); -const { textElems } = require('../plugins/_collections.js'); +const { textElems } = require('../plugins/_collections'); class SvgoParserError extends Error { /** diff --git a/lib/stringifier.js b/lib/stringifier.js index a33814b68..712d62fbc 100644 --- a/lib/stringifier.js +++ b/lib/stringifier.js @@ -12,7 +12,7 @@ * @typedef {import('./types').StringifyOptions} StringifyOptions */ -const { textElems } = require('../plugins/_collections.js'); +const { textElems } = require('../plugins/_collections'); /** * @typedef {{ diff --git a/plugins/_collections.js b/plugins/_collections.js index 5ef493e48..d264acd8c 100644 --- a/plugins/_collections.js +++ b/plugins/_collections.js @@ -93,13 +93,19 @@ exports.elemsGroups = { ], }; -exports.textElems = exports.elemsGroups.textContent.concat('title'); +/** + * Elements where adding or removing whitespace may effect rendering, metadata, + * or semantic meaning. + * + * @see https://developer.mozilla.org/docs/Web/HTML/Element/pre + */ +exports.textElems = [...exports.elemsGroups.textContent, 'title', 'pre']; exports.pathElems = ['path', 'glyph', 'missing-glyph']; -// https://www.w3.org/TR/SVG11/intro.html#Definitions /** * @type {Record>} + * @see https://www.w3.org/TR/SVG11/intro.html#Definitions */ exports.attrsGroups = { animationAddition: ['additive', 'accumulate'], @@ -363,7 +369,6 @@ exports.attrsGroupsDefaults = { }, }; -// https://www.w3.org/TR/SVG11/eltindex.html /** * @type {Record, @@ -372,6 +377,7 @@ exports.attrsGroupsDefaults = { * contentGroups?: Array, * content?: Array, * }>} + * @see https://www.w3.org/TR/SVG11/eltindex.html */ exports.elems = { a: { @@ -1948,7 +1954,9 @@ exports.editorNamespaces = [ 'http://www.vector.evaxdesign.sk', ]; -// https://www.w3.org/TR/SVG11/linking.html#processingIRI +/** + * @see https://www.w3.org/TR/SVG11/linking.html#processingIRI + */ exports.referencesProps = [ 'clip-path', 'color-profile', @@ -1962,7 +1970,9 @@ exports.referencesProps = [ 'style', ]; -// https://www.w3.org/TR/SVG11/propidx.html +/** + * @see https://www.w3.org/TR/SVG11/propidx.html + */ exports.inheritableAttrs = [ 'clip-rule', 'color', @@ -2216,7 +2226,9 @@ exports.colorsShortNames = { '#f5deb3': 'wheat', }; -// https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor +/** + * @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor + */ exports.colorsProps = [ 'color', 'fill', diff --git a/plugins/convertOneStopGradients.js b/plugins/convertOneStopGradients.js index bf94439ff..e5f4625d5 100644 --- a/plugins/convertOneStopGradients.js +++ b/plugins/convertOneStopGradients.js @@ -22,8 +22,8 @@ exports.description = * * @author Seth Falco * @type {import('./plugins-types').Plugin<'convertOneStopGradients'>} - * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient - * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient + * @see https://developer.mozilla.org/docs/Web/SVG/Element/linearGradient + * @see https://developer.mozilla.org/docs/Web/SVG/Element/radialGradient */ exports.fn = (root) => { const stylesheet = collectStylesheet(root); diff --git a/plugins/removeAttributesBySelector.js b/plugins/removeAttributesBySelector.js index 09db8a8d0..12630c2a0 100644 --- a/plugins/removeAttributesBySelector.js +++ b/plugins/removeAttributesBySelector.js @@ -69,7 +69,7 @@ exports.description = * ↓ * * - * @link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors + * @link https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors * * @author Bradley Mease * diff --git a/plugins/removeDesc.js b/plugins/removeDesc.js index 4520ed27c..f766350ea 100644 --- a/plugins/removeDesc.js +++ b/plugins/removeDesc.js @@ -12,7 +12,7 @@ const standardDescs = /^(Created with|Created using)/; * Removes only standard editors content or empty elements 'cause it can be used for accessibility. * Enable parameter 'removeAny' to remove any description. * - * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc + * https://developer.mozilla.org/docs/Web/SVG/Element/desc * * @author Daniel Wabyick * diff --git a/plugins/removeTitle.js b/plugins/removeTitle.js index ee136cd56..906dd3c20 100644 --- a/plugins/removeTitle.js +++ b/plugins/removeTitle.js @@ -8,7 +8,7 @@ exports.description = 'removes '; /** * Remove <title>. * - * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title + * https://developer.mozilla.org/docs/Web/SVG/Element/title * * @author Igor Kalashnikov * diff --git a/plugins/reusePaths.js b/plugins/reusePaths.js index 1704b16b2..89ff1f6be 100644 --- a/plugins/reusePaths.js +++ b/plugins/reusePaths.js @@ -36,7 +36,7 @@ exports.fn = (root) => { * element if one exists. * * @type {XastElement} - * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs + * @see https://developer.mozilla.org/docs/Web/SVG/Element/defs */ let svgDefs; diff --git a/test/svgo/_index.test.js b/test/svgo/_index.test.js index f21eb15c6..5ac5013b6 100644 --- a/test/svgo/_index.test.js +++ b/test/svgo/_index.test.js @@ -69,4 +69,19 @@ describe('svgo', () => { }); expect(normalize(result.data)).toEqual(expected); }); + it('should not trim whitespace at start and end of pre element', async () => { + const [original, expected] = await parseFixture('pre-element.svg'); + const result = optimize(original, { + path: 'input.svg', + }); + expect(normalize(result.data)).toEqual(expected); + }); + it('should not add whitespace in pre element', async () => { + const [original, expected] = await parseFixture('pre-element-pretty.svg'); + const result = optimize(original, { + path: 'input.svg', + js2svg: { pretty: true }, + }); + expect(normalize(result.data)).toEqual(expected); + }); }); diff --git a/test/svgo/pre-element-pretty.svg b/test/svgo/pre-element-pretty.svg new file mode 100644 index 000000000..692bbcef1 --- /dev/null +++ b/test/svgo/pre-element-pretty.svg @@ -0,0 +1,37 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 854 340"> + <foreignObject width="100%" height="100%"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <pre style="text-align:center"> OOO PPPP EEEEE N N SSSSS OOO U U RRRR CCCC EEEEE +O O P P E NN N SS O O U U R R C E +O O PPPP EEE N N N SSS O O U U RRRR C EEE +O O P E N NN SS O O U U R R C E + OOO P EEEEE N N SSSSS OOO UUU R R CCCC EEEEE + +M M AAA IIIII N N TTTTT AAA IIIII N N EEEEE RRRR +MM MM A A I NN N T A A I NN N E R R +M M M AAAAA I N N N T AAAAA I N N N EEE RRRR +M M A A I N NN T A A I N NN E R R +M M A A IIIII N N T A A IIIII N N EEEEE R R </pre> + </div> + </foreignObject> +</svg> + +@@@ + +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 854 340"> + <foreignObject width="100%" height="100%"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <pre style="text-align:center"> OOO PPPP EEEEE N N SSSSS OOO U U RRRR CCCC EEEEE +O O P P E NN N SS O O U U R R C E +O O PPPP EEE N N N SSS O O U U RRRR C EEE +O O P E N NN SS O O U U R R C E + OOO P EEEEE N N SSSSS OOO UUU R R CCCC EEEEE + +M M AAA IIIII N N TTTTT AAA IIIII N N EEEEE RRRR +MM MM A A I NN N T A A I NN N E R R +M M M AAAAA I N N N T AAAAA I N N N EEE RRRR +M M A A I N NN T A A I N NN E R R +M M A A IIIII N N T A A IIIII N N EEEEE R R </pre> + </div> + </foreignObject> +</svg> diff --git a/test/svgo/pre-element.svg b/test/svgo/pre-element.svg new file mode 100644 index 000000000..71a6f9525 --- /dev/null +++ b/test/svgo/pre-element.svg @@ -0,0 +1,31 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 854 340"> + <foreignObject width="100%" height="100%"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <pre style="text-align:center"> OOO PPPP EEEEE N N SSSSS OOO U U RRRR CCCC EEEEE +O O P P E NN N SS O O U U R R C E +O O PPPP EEE N N N SSS O O U U RRRR C EEE +O O P E N NN SS O O U U R R C E + OOO P EEEEE N N SSSSS OOO UUU R R CCCC EEEEE + +M M AAA IIIII N N TTTTT AAA IIIII N N EEEEE RRRR +MM MM A A I NN N T A A I NN N E R R +M M M AAAAA I N N N T AAAAA I N N N EEE RRRR +M M A A I N NN T A A I N NN E R R +M M A A IIIII N N T A A IIIII N N EEEEE R R </pre> + </div> + </foreignObject> +</svg> + +@@@ + +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 854 340"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml"><pre style="text-align:center"> OOO PPPP EEEEE N N SSSSS OOO U U RRRR CCCC EEEEE +O O P P E NN N SS O O U U R R C E +O O PPPP EEE N N N SSS O O U U RRRR C EEE +O O P E N NN SS O O U U R R C E + OOO P EEEEE N N SSSSS OOO UUU R R CCCC EEEEE + +M M AAA IIIII N N TTTTT AAA IIIII N N EEEEE RRRR +MM MM A A I NN N T A A I NN N E R R +M M M AAAAA I N N N T AAAAA I N N N EEE RRRR +M M A A I N NN T A A I N NN E R R +M M A A IIIII N N T A A IIIII N N EEEEE R R </pre></div></foreignObject></svg>