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';
exports.type = 'perItem';
exports.type = 'visitor';
exports.active = true;
exports.description =
'cleanups attributes from newlines, trailing and repeating spaces';
exports.params = {
newlines: true,
trim: true,
spaces: true,
};
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
regNewlines = /\r?\n/g,
regSpaces = /\s{2,}/g;
const regNewlinesNeedSpace = /(\S)\r?\n(\S)/g;
const regNewlines = /\r?\n/g;
const regSpaces = /\s{2,}/g;
/**
* 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
*/
exports.fn = function (item, params) {
if (item.type === 'element') {
for (const name of Object.keys(item.attributes)) {
if (params.newlines) {
// new line which requires a space instead of themselve
item.attributes[name] = item.attributes[name].replace(
regNewlinesNeedSpace,
(match, p1, p2) => p1 + ' ' + p2
);
// simple new line
item.attributes[name] = item.attributes[name].replace(regNewlines, '');
}
if (params.trim) {
item.attributes[name] = item.attributes[name].trim();
}
if (params.spaces) {
item.attributes[name] = item.attributes[name].replace(regSpaces, ' ');
}
}
}
exports.fn = (root, params) => {
const { newlines = true, trim = true, spaces = true } = params;
return {
element: {
enter: (node) => {
for (const name of Object.keys(node.attributes)) {
if (newlines) {
// new line which requires a space instead of themselve
node.attributes[name] = node.attributes[name].replace(
regNewlinesNeedSpace,
(match, p1, p2) => p1 + ' ' + p2
);
// simple new line
node.attributes[name] = node.attributes[name].replace(
regNewlines,
''
);
}
if (trim) {
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';
exports.type = 'perItem';
exports.type = 'visitor';
exports.active = true;
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
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Taylor Hunt
*/
exports.fn = function (item) {
if (item.isElem('ellipse')) {
const rx = item.attributes.rx || 0;
const ry = item.attributes.ry || 0;
if (
rx === ry ||
rx === 'auto' ||
ry === 'auto' // SVG2
) {
var radius = rx !== 'auto' ? rx : ry;
item.renameElem('circle');
delete item.attributes.rx;
delete item.attributes.ry;
item.attributes.r = radius;
}
}
exports.fn = () => {
return {
element: {
enter: (node) => {
if (node.name === 'ellipse') {
const rx = node.attributes.rx || 0;
const ry = node.attributes.ry || 0;
if (
rx === ry ||
rx === 'auto' ||
ry === 'auto' // SVG2
) {
node.name = 'circle';
const radius = rx === 'auto' ? ry : rx;
delete node.attributes.rx;
delete node.attributes.ry;
node.attributes.r = radius;
}
}
},
},
};
};

View File

@ -1,16 +1,12 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.params = {
removeAny: true,
};
exports.description = 'removes <desc>';
var standardDescs = /^(Created with|Created using)/;
const standardDescs = /^(Created with|Created using)/;
/**
* Removes <desc>.
@ -19,19 +15,24 @@ var standardDescs = /^(Created with|Created using)/;
*
* 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
*/
exports.fn = function (item, params) {
return (
!item.isElem('desc') ||
!(
params.removeAny ||
item.children.length === 0 ||
(item.children[0].type === 'text' &&
standardDescs.test(item.children[0].value))
)
);
exports.fn = (root, params) => {
const { removeAny = true } = params;
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'desc') {
if (
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';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.description = 'removes doctype declaration';
/**
@ -26,13 +26,14 @@ exports.description = 'removes doctype declaration';
* <!-- 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
*/
exports.fn = function (item) {
if (item.type === 'doctype') {
return false;
}
exports.fn = () => {
return {
doctype: {
enter: (node, parentNode) => {
detachNodeFromParent(node, parentNode);
},
},
};
};

View File

@ -1,17 +1,11 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.description = 'removes empty <text> elements';
exports.params = {
text: true,
tspan: true,
tref: true,
};
/**
* Remove empty Text elements.
*
@ -27,31 +21,30 @@ exports.params = {
* Remove tref with empty xlink:href attribute:
* <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
*/
exports.fn = function (item, params) {
if (item.type === 'element') {
// Remove empty text element
if (params.text && item.name === 'text' && item.children.length === 0) {
return false;
}
// Remove empty tspan element
if (params.tspan && item.name === 'tspan' && item.children.length === 0) {
return false;
}
// Remove tref with empty xlink:href attribute
if (
params.tref &&
item.name === 'tref' &&
item.attributes['xlink:href'] == null
) {
return false;
}
}
exports.fn = (root, params) => {
const { text = true, tspan = true, tref = true } = params;
return {
element: {
enter: (node, parentNode) => {
// Remove empty text element
if (text && node.name === 'text' && node.children.length === 0) {
detachNodeFromParent(node, parentNode);
}
// Remove empty tspan element
if (tspan && node.name === 'tspan' && node.children.length === 0) {
detachNodeFromParent(node, parentNode);
}
// Remove tref with empty xlink:href attribute
if (
tref &&
node.name === 'tref' &&
node.attributes['xlink:href'] == null
) {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.description = 'removes <metadata>';
/**
@ -11,11 +11,16 @@ exports.description = 'removes <metadata>';
*
* 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
*/
exports.fn = function (item) {
return !item.isElem('metadata');
exports.fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'metadata') {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false;
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
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function (item) {
if (
item.type === 'element' &&
item.name === 'image' &&
item.attributes['xlink:href'] != null &&
/(\.|image\/)(jpg|png|gif)/.test(item.attributes['xlink:href'])
) {
return false;
}
exports.fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (
node.name === 'image' &&
node.attributes['xlink:href'] != null &&
/(\.|image\/)(jpg|png|gif)/.test(node.attributes['xlink:href'])
) {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false;
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
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Patrick Klingemann
*/
exports.fn = function (item) {
return !item.isElem('script');
exports.fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'script') {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = false;
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
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Betsy Dupuis
*/
exports.fn = function (item) {
return !item.isElem('style');
exports.fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'style') {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.description = 'removes <title>';
/**
@ -11,11 +11,16 @@ exports.description = 'removes <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
*/
exports.fn = function (item) {
return !item.isElem('title');
exports.fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'title') {
detachNodeFromParent(node, parentNode);
}
},
},
};
};

View File

@ -1,9 +1,9 @@
'use strict';
exports.type = 'perItem';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.type = 'visitor';
exports.active = true;
exports.description = 'removes XML processing instructions';
/**
@ -12,14 +12,16 @@ exports.description = 'removes XML processing instructions';
* @example
* <?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
*/
exports.fn = function (item) {
if (item.type === 'instruction' && item.name === 'xml') {
return false;
}
return true;
exports.fn = () => {
return {
instruction: {
enter: (node, parentNode) => {
if (node.name === 'xml') {
detachNodeFromParent(node, parentNode);
}
},
},
};
};