1
0
mirror of https://github.com/svg/svgo.git synced 2025-07-29 20:21:14 +03:00

Refactor basic plugins with visitor api (#1518)

- cleanupAttrs
- convertEllipseToCircle
- removeDesc
- removeDoctype
- removeEmptyText
- removeMetadata
- removeRasterImages
- removeScriptElement
- removeStyleElement
- removeTitle
- removeXMLProcInst
This commit is contained in:
Bogdan Chadkin
2021-08-12 14:57:36 +03:00
committed by GitHub
parent 35b7356ff0
commit f00bd727b0
11 changed files with 191 additions and 175 deletions

View File

@ -1,52 +1,48 @@
'use strict'; 'use strict';
exports.type = 'perItem'; exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = exports.description =
'cleanups attributes from newlines, trailing and repeating spaces'; 'cleanups attributes from newlines, trailing and repeating spaces';
exports.params = { const regNewlinesNeedSpace = /(\S)\r?\n(\S)/g;
newlines: true, const regNewlines = /\r?\n/g;
trim: true, const regSpaces = /\s{2,}/g;
spaces: true,
};
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
regNewlines = /\r?\n/g,
regSpaces = /\s{2,}/g;
/** /**
* Cleanup attributes values from newlines, trailing and repeating spaces. * Cleanup attributes values from newlines, trailing and repeating spaces.
* *
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item, params) { exports.fn = (root, params) => {
if (item.type === 'element') { const { newlines = true, trim = true, spaces = true } = params;
for (const name of Object.keys(item.attributes)) { return {
if (params.newlines) { element: {
// new line which requires a space instead of themselve enter: (node) => {
item.attributes[name] = item.attributes[name].replace( for (const name of Object.keys(node.attributes)) {
regNewlinesNeedSpace, if (newlines) {
(match, p1, p2) => p1 + ' ' + p2 // new line which requires a space instead of themselve
); node.attributes[name] = node.attributes[name].replace(
regNewlinesNeedSpace,
// simple new line (match, p1, p2) => p1 + ' ' + p2
item.attributes[name] = item.attributes[name].replace(regNewlines, ''); );
} // simple new line
node.attributes[name] = node.attributes[name].replace(
if (params.trim) { regNewlines,
item.attributes[name] = item.attributes[name].trim(); ''
} );
}
if (params.spaces) { if (trim) {
item.attributes[name] = item.attributes[name].replace(regSpaces, ' '); node.attributes[name] = node.attributes[name].trim();
} }
} if (spaces) {
} node.attributes[name] = node.attributes[name].replace(
regSpaces,
' '
);
}
}
},
},
};
}; };

View File

@ -1,9 +1,7 @@
'use strict'; 'use strict';
exports.type = 'perItem'; exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'converts non-eccentric <ellipse>s to <circle>s'; exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
/** /**
@ -11,26 +9,28 @@ exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
* *
* @see https://www.w3.org/TR/SVG11/shapes.html * @see https://www.w3.org/TR/SVG11/shapes.html
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Taylor Hunt * @author Taylor Hunt
*/ */
exports.fn = function (item) { exports.fn = () => {
if (item.isElem('ellipse')) { return {
const rx = item.attributes.rx || 0; element: {
const ry = item.attributes.ry || 0; enter: (node) => {
if (node.name === 'ellipse') {
if ( const rx = node.attributes.rx || 0;
rx === ry || const ry = node.attributes.ry || 0;
rx === 'auto' || if (
ry === 'auto' // SVG2 rx === ry ||
) { rx === 'auto' ||
var radius = rx !== 'auto' ? rx : ry; ry === 'auto' // SVG2
item.renameElem('circle'); ) {
delete item.attributes.rx; node.name = 'circle';
delete item.attributes.ry; const radius = rx === 'auto' ? ry : rx;
item.attributes.r = radius; delete node.attributes.rx;
} delete node.attributes.ry;
} node.attributes.r = radius;
}
}
},
},
};
}; };

View File

@ -1,16 +1,12 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.params = {
removeAny: true,
};
exports.description = 'removes <desc>'; exports.description = 'removes <desc>';
var standardDescs = /^(Created with|Created using)/; const standardDescs = /^(Created with|Created using)/;
/** /**
* Removes <desc>. * Removes <desc>.
@ -19,19 +15,24 @@ var standardDescs = /^(Created with|Created using)/;
* *
* https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Daniel Wabyick * @author Daniel Wabyick
*/ */
exports.fn = function (item, params) { exports.fn = (root, params) => {
return ( const { removeAny = true } = params;
!item.isElem('desc') || return {
!( element: {
params.removeAny || enter: (node, parentNode) => {
item.children.length === 0 || if (node.name === 'desc') {
(item.children[0].type === 'text' && if (
standardDescs.test(item.children[0].value)) removeAny ||
) node.children.length === 0 ||
); (node.children[0].type === 'text' &&
standardDescs.test(node.children[0].value))
) {
detachNodeFromParent(node, parentNode);
}
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'removes doctype declaration'; exports.description = 'removes doctype declaration';
/** /**
@ -26,13 +26,14 @@ exports.description = 'removes doctype declaration';
* <!-- an internal subset can be embedded here --> * <!-- an internal subset can be embedded here -->
* ]> * ]>
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item) { exports.fn = () => {
if (item.type === 'doctype') { return {
return false; doctype: {
} enter: (node, parentNode) => {
detachNodeFromParent(node, parentNode);
},
},
};
}; };

View File

@ -1,17 +1,11 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'removes empty <text> elements'; exports.description = 'removes empty <text> elements';
exports.params = {
text: true,
tspan: true,
tref: true,
};
/** /**
* Remove empty Text elements. * Remove empty Text elements.
* *
@ -27,31 +21,30 @@ exports.params = {
* Remove tref with empty xlink:href attribute: * Remove tref with empty xlink:href attribute:
* <tref xlink:href=""/> * <tref xlink:href=""/>
* *
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item, params) { exports.fn = (root, params) => {
if (item.type === 'element') { const { text = true, tspan = true, tref = true } = params;
// Remove empty text element return {
if (params.text && item.name === 'text' && item.children.length === 0) { element: {
return false; enter: (node, parentNode) => {
} // Remove empty text element
if (text && node.name === 'text' && node.children.length === 0) {
// Remove empty tspan element detachNodeFromParent(node, parentNode);
if (params.tspan && item.name === 'tspan' && item.children.length === 0) { }
return false; // Remove empty tspan element
} if (tspan && node.name === 'tspan' && node.children.length === 0) {
detachNodeFromParent(node, parentNode);
// Remove tref with empty xlink:href attribute }
if ( // Remove tref with empty xlink:href attribute
params.tref && if (
item.name === 'tref' && tref &&
item.attributes['xlink:href'] == null node.name === 'tref' &&
) { node.attributes['xlink:href'] == null
return false; ) {
} detachNodeFromParent(node, parentNode);
} }
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'removes <metadata>'; exports.description = 'removes <metadata>';
/** /**
@ -11,11 +11,16 @@ exports.description = 'removes <metadata>';
* *
* https://www.w3.org/TR/SVG11/metadata.html * https://www.w3.org/TR/SVG11/metadata.html
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item) { exports.fn = () => {
return !item.isElem('metadata'); return {
element: {
enter: (node, parentNode) => {
if (node.name === 'metadata') {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false; exports.active = false;
exports.description = 'removes raster images (disabled by default)'; exports.description = 'removes raster images (disabled by default)';
/** /**
@ -11,18 +11,20 @@ exports.description = 'removes raster images (disabled by default)';
* *
* @see https://bugs.webkit.org/show_bug.cgi?id=63548 * @see https://bugs.webkit.org/show_bug.cgi?id=63548
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item) { exports.fn = () => {
if ( return {
item.type === 'element' && element: {
item.name === 'image' && enter: (node, parentNode) => {
item.attributes['xlink:href'] != null && if (
/(\.|image\/)(jpg|png|gif)/.test(item.attributes['xlink:href']) node.name === 'image' &&
) { node.attributes['xlink:href'] != null &&
return false; /(\.|image\/)(jpg|png|gif)/.test(node.attributes['xlink:href'])
} ) {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false; exports.active = false;
exports.description = 'removes <script> elements (disabled by default)'; exports.description = 'removes <script> elements (disabled by default)';
/** /**
@ -11,11 +11,17 @@ exports.description = 'removes <script> elements (disabled by default)';
* *
* https://www.w3.org/TR/SVG11/script.html * https://www.w3.org/TR/SVG11/script.html
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
* *
* @author Patrick Klingemann * @author Patrick Klingemann
*/ */
exports.fn = function (item) { exports.fn = () => {
return !item.isElem('script'); return {
element: {
enter: (node, parentNode) => {
if (node.name === 'script') {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false; exports.active = false;
exports.description = 'removes <style> element (disabled by default)'; exports.description = 'removes <style> element (disabled by default)';
/** /**
@ -11,11 +11,16 @@ exports.description = 'removes <style> element (disabled by default)';
* *
* https://www.w3.org/TR/SVG11/styling.html#StyleElement * https://www.w3.org/TR/SVG11/styling.html#StyleElement
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Betsy Dupuis * @author Betsy Dupuis
*/ */
exports.fn = function (item) { exports.fn = () => {
return !item.isElem('style'); return {
element: {
enter: (node, parentNode) => {
if (node.name === 'style') {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'removes <title>'; exports.description = 'removes <title>';
/** /**
@ -11,11 +11,16 @@ exports.description = 'removes <title>';
* *
* https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Igor Kalashnikov * @author Igor Kalashnikov
*/ */
exports.fn = function (item) { exports.fn = () => {
return !item.isElem('title'); return {
element: {
enter: (node, parentNode) => {
if (node.name === 'title') {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
exports.type = 'perItem'; const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true; exports.active = true;
exports.description = 'removes XML processing instructions'; exports.description = 'removes XML processing instructions';
/** /**
@ -12,14 +12,16 @@ exports.description = 'removes XML processing instructions';
* @example * @example
* <?xml version="1.0" encoding="utf-8"?> * <?xml version="1.0" encoding="utf-8"?>
* *
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich * @author Kir Belevich
*/ */
exports.fn = function (item) { exports.fn = () => {
if (item.type === 'instruction' && item.name === 'xml') { return {
return false; instruction: {
} enter: (node, parentNode) => {
return true; if (node.name === 'xml') {
detachNodeFromParent(node, parentNode);
}
},
},
};
}; };