From 07928fc77e6a9da7c5e3cffc023e7115be1cc551 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Wed, 17 Mar 2021 21:40:06 +0300 Subject: [PATCH] Replace removeAttr with delete operator (#1432) delete operator is more explicit and not much harder to use. --- lib/svgo/jsAPI.js | 27 +++++++++++--------- plugins/_applyTransforms.js | 2 +- plugins/cleanupEnableBackground.js | 28 ++++++++++---------- plugins/cleanupIDs.js | 4 +-- plugins/collapseGroups.js | 4 +-- plugins/convertEllipseToCircle.js | 13 ++++------ plugins/convertShapeToPath.js | 26 +++++++++++++++---- plugins/convertStyleToAttrs.js | 2 +- plugins/convertTransform.js | 4 +-- plugins/inlineStyles.js | 6 +++-- plugins/moveElemsAttrsToGroup.js | 2 +- plugins/moveGroupAttrsToElems.js | 5 ++-- plugins/removeAttributesBySelector.js | 12 ++++++--- plugins/removeAttrs.js | 2 +- plugins/removeDimensions.js | 31 ++++++++++------------- plugins/removeEditorsNSData.js | 13 +++++----- plugins/removeEmptyAttrs.js | 2 +- plugins/removeNonInheritableGroupAttrs.js | 2 +- plugins/removeUnknownsAndDefaults.js | 12 ++++----- plugins/removeUnusedNS.js | 8 +++--- plugins/removeUselessStrokeAndFill.js | 19 +++++--------- plugins/removeViewBox.js | 21 +++++++-------- plugins/removeXMLNS.js | 4 +-- plugins/reusePaths.js | 10 ++++---- 24 files changed, 138 insertions(+), 121 deletions(-) diff --git a/lib/svgo/jsAPI.js b/lib/svgo/jsAPI.js index 1bf5af7e..29a1cc1d 100644 --- a/lib/svgo/jsAPI.js +++ b/lib/svgo/jsAPI.js @@ -307,20 +307,23 @@ JSAPI.prototype.computedAttr = function (name, val) { * @param {String} [val] attribute value * @return {Boolean} */ -JSAPI.prototype.removeAttr = function (name, val, recursive) { - if (!arguments.length) return false; - - if (Array.isArray(name)) { - name.forEach(this.removeAttr, this); +JSAPI.prototype.removeAttr = function (name, val) { + if (this.type !== 'element') { return false; } - - if (!this.hasAttr(name)) return false; - - if (!recursive && val && this.attrs[name].value !== val) return false; - - delete this.attrs[name]; - + if (arguments.length === 0) { + return false; + } + if (Array.isArray(name)) { + for (const nameItem of name) { + this.removeAttr(nameItem, val); + } + return false; + } + if (this.hasAttr(name, val) === false) { + return false; + } + delete this.attributes[name]; return true; }; diff --git a/plugins/_applyTransforms.js b/plugins/_applyTransforms.js index 591dd52f..6d450de6 100644 --- a/plugins/_applyTransforms.js +++ b/plugins/_applyTransforms.js @@ -118,7 +118,7 @@ const applyTransforms = (elem, pathData, params) => { applyMatrixToPathData(pathData, matrix.data); // remove transform attr - elem.removeAttr('transform'); + delete elem.attributes.transform; return; }; diff --git a/plugins/cleanupEnableBackground.js b/plugins/cleanupEnableBackground.js index 2369d6c0..5ef55193 100644 --- a/plugins/cleanupEnableBackground.js +++ b/plugins/cleanupEnableBackground.js @@ -30,23 +30,23 @@ exports.fn = function (data) { function checkEnableBackground(item) { if ( item.isElem(elems) && - item.hasAttr('enable-background') && - item.hasAttr('width') && - item.hasAttr('height') + item.attributes['enable-background'] != null && + item.attributes.width != null && + item.attributes.height != null ) { - var match = item - .attr('enable-background') - .value.match(regEnableBackground); + var match = item.attributes['enable-background'].match( + regEnableBackground + ); if (match) { if ( - item.attr('width').value === match[1] && - item.attr('height').value === match[3] + item.attributes.width === match[1] && + item.attributes.height === match[3] ) { if (item.isElem('svg')) { - item.removeAttr('enable-background'); + delete item.attributes['enable-background']; } else { - item.attr('enable-background').value = 'new'; + item.attributes['enable-background'] = 'new'; } } } @@ -79,8 +79,10 @@ exports.fn = function (data) { return hasFilter ? firstStep - : monkeys(firstStep, function (item) { - //we don't need 'enable-background' if we have no filters - item.removeAttr('enable-background'); + : monkeys(firstStep, (item) => { + if (item.type === 'element') { + //we don't need 'enable-background' if we have no filters + delete item.attributes['enable-background']; + } }); }; diff --git a/plugins/cleanupIDs.js b/plugins/cleanupIDs.js index e943e011..d9ec43dd 100644 --- a/plugins/cleanupIDs.js +++ b/plugins/cleanupIDs.js @@ -154,7 +154,7 @@ exports.fn = function (data, params) { if (name === 'id') { key = value; if (IDs.has(key)) { - item.removeAttr('id'); // remove repeated id + delete item.attributes.id; // remove repeated id } else { IDs.set(key, item); } @@ -230,7 +230,7 @@ exports.fn = function (data, params) { if (params.remove) { for (var keyElem of IDs) { if (!idPreserved(keyElem[0])) { - keyElem[1].removeAttr('id'); + delete keyElem[1].attributes.id; } } } diff --git a/plugins/collapseGroups.js b/plugins/collapseGroups.js index 5a82aa08..d75c5615 100644 --- a/plugins/collapseGroups.js +++ b/plugins/collapseGroups.js @@ -46,7 +46,7 @@ exports.fn = function (item) { // non-empty elements if ( item.type === 'element' && - !item.isElem('switch') && + item.name !== 'switch' && item.children.length !== 0 ) { item.children.forEach(function (g, i) { @@ -82,7 +82,7 @@ exports.fn = function (item) { return; } - g.removeAttr(name); + delete g.attributes[name]; } } } diff --git a/plugins/convertEllipseToCircle.js b/plugins/convertEllipseToCircle.js index b08f2527..2560b3ae 100644 --- a/plugins/convertEllipseToCircle.js +++ b/plugins/convertEllipseToCircle.js @@ -18,8 +18,8 @@ exports.description = 'converts non-eccentric s to s'; */ exports.fn = function (item) { if (item.isElem('ellipse')) { - var rx = (item.hasAttr('rx') && item.attr('rx').value) || 0; - var ry = (item.hasAttr('ry') && item.attr('ry').value) || 0; + const rx = item.attributes.rx || 0; + const ry = item.attributes.ry || 0; if ( rx === ry || @@ -28,12 +28,9 @@ exports.fn = function (item) { ) { var radius = rx !== 'auto' ? rx : ry; item.renameElem('circle'); - item.removeAttr(['rx', 'ry']); - item.addAttr({ - name: 'r', - value: radius, - }); + delete item.attributes.rx; + delete item.attributes.ry; + item.attributes.r = radius; } } - return; }; diff --git a/plugins/convertShapeToPath.js b/plugins/convertShapeToPath.js index 3b861b90..25caf53e 100644 --- a/plugins/convertShapeToPath.js +++ b/plugins/convertShapeToPath.js @@ -59,7 +59,11 @@ exports.fn = function (item, params) { name: 'd', value: stringifyPathData({ pathData, precision }), }); - item.renameElem('path').removeAttr(['x', 'y', 'width', 'height']); + item.renameElem('path'); + delete item.attributes.x; + delete item.attributes.y; + delete item.attributes.width; + delete item.attributes.height; } if (item.isElem('line')) { @@ -76,7 +80,11 @@ exports.fn = function (item, params) { name: 'd', value: stringifyPathData({ pathData, precision }), }); - item.renameElem('path').removeAttr(['x1', 'y1', 'x2', 'y2']); + item.renameElem('path'); + delete item.attributes.x1; + delete item.attributes.y1; + delete item.attributes.x2; + delete item.attributes.y2; } if ( @@ -99,7 +107,8 @@ exports.fn = function (item, params) { name: 'd', value: stringifyPathData({ pathData, precision }), }); - item.renameElem('path').removeAttr('points'); + item.renameElem('path'); + delete item.attributes.points; } if (item.isElem('circle') && convertArcs) { @@ -119,7 +128,10 @@ exports.fn = function (item, params) { name: 'd', value: stringifyPathData({ pathData, precision }), }); - item.renameElem('path').removeAttr(['cx', 'cy', 'r']); + item.renameElem('path'); + delete item.attributes.cx; + delete item.attributes.cy; + delete item.attributes.r; } if (item.isElem('ellipse') && convertArcs) { @@ -140,6 +152,10 @@ exports.fn = function (item, params) { name: 'd', value: stringifyPathData({ pathData, precision }), }); - item.renameElem('path').removeAttr(['cx', 'cy', 'rx', 'ry']); + item.renameElem('path'); + delete item.attributes.cx; + delete item.attributes.cy; + delete item.attributes.rx; + delete item.attributes.ry; } }; diff --git a/plugins/convertStyleToAttrs.js b/plugins/convertStyleToAttrs.js index 152d45d2..739347e9 100644 --- a/plugins/convertStyleToAttrs.js +++ b/plugins/convertStyleToAttrs.js @@ -122,7 +122,7 @@ exports.fn = function (item, params) { }) .join(';'); } else { - item.removeAttr('style'); + delete item.attributes.style; } } } diff --git a/plugins/convertTransform.js b/plugins/convertTransform.js index 3e6f7a43..d0128d24 100644 --- a/plugins/convertTransform.js +++ b/plugins/convertTransform.js @@ -88,9 +88,9 @@ function convertTransform(item, attrName, params) { } if (data.length) { - item.attr(attrName).value = js2transform(data, params); + item.attributes[attrName] = js2transform(data, params); } else { - item.removeAttr(attrName); + delete item.attributes[attrName]; } } diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 67e1bdc7..d7c9de65 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -207,12 +207,14 @@ exports.fn = function (document, opts) { } // clean up now empty class attributes if (typeof selectedEl.class.item(0) === 'undefined') { - selectedEl.removeAttr('class'); + delete selectedEl.attributes.class; } // ID if (firstSubSelector.type === 'IdSelector') { - selectedEl.removeAttr('id', firstSubSelector.name); + if (selectedEl.attributes.id === firstSubSelector.name) { + delete selectedEl.attributes.id; + } } } } diff --git a/plugins/moveElemsAttrsToGroup.js b/plugins/moveElemsAttrsToGroup.js index 66eb741f..14644a49 100644 --- a/plugins/moveElemsAttrsToGroup.js +++ b/plugins/moveElemsAttrsToGroup.js @@ -64,7 +64,7 @@ exports.fn = function (item) { item.children.forEach(function (g) { for (const [name, value] of Object.entries(intersection)) { if ((!allPath && !hasClip) || name !== 'transform') { - g.removeAttr(name); + delete g.attributes[name]; if (name === 'transform') { if (!hasTransform) { diff --git a/plugins/moveGroupAttrsToElems.js b/plugins/moveGroupAttrsToElems.js index 2d29e7c3..ce6f1983 100644 --- a/plugins/moveGroupAttrsToElems.js +++ b/plugins/moveGroupAttrsToElems.js @@ -32,7 +32,8 @@ var collections = require('./_collections.js'), exports.fn = function (item) { // move group transform attr to content's pathElems if ( - item.isElem('g') && + item.type === 'element' && + item.name === 'g' && item.children.length !== 0 && item.attributes.transform != null && Object.entries(item.attributes).some( @@ -52,6 +53,6 @@ exports.fn = function (item) { } } - item.removeAttr('transform'); + delete item.attributes.transform; } }; diff --git a/plugins/removeAttributesBySelector.js b/plugins/removeAttributesBySelector.js index a5fc4c6a..1f51e739 100644 --- a/plugins/removeAttributesBySelector.js +++ b/plugins/removeAttributesBySelector.js @@ -60,9 +60,15 @@ exports.description = exports.fn = function (item, params) { var selectors = Array.isArray(params.selectors) ? params.selectors : [params]; - selectors.map(function (i) { - if (item.matches(i.selector)) { - item.removeAttr(i.attributes); + selectors.map(({ selector, attributes }) => { + if (item.matches(selector)) { + if (Array.isArray(attributes)) { + for (const name of attributes) { + delete item.attributes[name]; + } + } else { + delete item.attributes[attributes]; + } } }); }; diff --git a/plugins/removeAttrs.js b/plugins/removeAttrs.js index 4c8e53ed..c54d6664 100644 --- a/plugins/removeAttrs.js +++ b/plugins/removeAttrs.js @@ -135,7 +135,7 @@ exports.fn = function (item, params) { if (pattern[1].test(name)) { // matches attribute value if (pattern[2].test(value)) { - item.removeAttr(name); + delete item.attributes[name]; } } } diff --git a/plugins/removeDimensions.js b/plugins/removeDimensions.js index 292add9b..0de6c1b6 100644 --- a/plugins/removeDimensions.js +++ b/plugins/removeDimensions.js @@ -21,26 +21,21 @@ exports.description = * @author Benny Schudel */ exports.fn = function (item) { - if (item.isElem('svg')) { - if (item.hasAttr('viewBox')) { - item.removeAttr('width'); - item.removeAttr('height'); + if (item.type === 'element' && item.name === 'svg') { + if (item.attributes.viewBox != null) { + delete item.attributes.width; + delete item.attributes.height; } else if ( - item.hasAttr('width') && - item.hasAttr('height') && - !isNaN(Number(item.attr('width').value)) && - !isNaN(Number(item.attr('height').value)) + item.attributes.width != null && + item.attributes.height != null && + Number.isNaN(Number(item.attributes.width)) === false && + Number.isNaN(Number(item.attributes.height)) === false ) { - item.addAttr({ - name: 'viewBox', - value: - '0 0 ' + - Number(item.attr('width').value) + - ' ' + - Number(item.attr('height').value), - }); - item.removeAttr('width'); - item.removeAttr('height'); + const width = Number(item.attributes.width); + const height = Number(item.attributes.height); + item.attributes.viewBox = `0 0 ${width} ${height}`; + delete item.attributes.width; + delete item.attributes.height; } } }; diff --git a/plugins/removeEditorsNSData.js b/plugins/removeEditorsNSData.js index 8220d018..f966b458 100644 --- a/plugins/removeEditorsNSData.js +++ b/plugins/removeEditorsNSData.js @@ -1,6 +1,7 @@ 'use strict'; const { parseName } = require('../lib/svgo/tools.js'); +const { editorNamespaces } = require('./_collections'); exports.type = 'perItem'; @@ -8,8 +9,7 @@ exports.active = true; exports.description = 'removes editors namespaces, elements and attributes'; -var editorNamespaces = require('./_collections').editorNamespaces, - prefixes = []; +const prefixes = []; exports.params = { additionalNamespaces: [], @@ -30,19 +30,20 @@ exports.params = { * @author Kir Belevich */ exports.fn = function (item, params) { + let namespaces = editorNamespaces; if (Array.isArray(params.additionalNamespaces)) { - editorNamespaces = editorNamespaces.concat(params.additionalNamespaces); + namespaces = [...editorNamespaces, ...params.additionalNamespaces]; } if (item.type === 'element') { if (item.isElem('svg')) { for (const [name, value] of Object.entries(item.attributes)) { const { prefix, local } = parseName(name); - if (prefix === 'xmlns' && editorNamespaces.includes(value)) { + if (prefix === 'xmlns' && namespaces.includes(value)) { prefixes.push(local); // - item.removeAttr(name); + delete item.attributes[name]; } } } @@ -51,7 +52,7 @@ exports.fn = function (item, params) { for (const name of Object.keys(item.attributes)) { const { prefix } = parseName(name); if (prefixes.includes(prefix)) { - item.removeAttr(name); + delete item.attributes[name]; } } diff --git a/plugins/removeEmptyAttrs.js b/plugins/removeEmptyAttrs.js index bce6c452..9d4e32a7 100644 --- a/plugins/removeEmptyAttrs.js +++ b/plugins/removeEmptyAttrs.js @@ -24,7 +24,7 @@ exports.fn = function (item) { // empty conditional processing attributes prevents elements from rendering attrsGroups.conditionalProcessing.includes(name) === false ) { - item.removeAttr(name); + delete item.attributes[name]; } } } diff --git a/plugins/removeNonInheritableGroupAttrs.js b/plugins/removeNonInheritableGroupAttrs.js index d1cab3bc..d99045f8 100644 --- a/plugins/removeNonInheritableGroupAttrs.js +++ b/plugins/removeNonInheritableGroupAttrs.js @@ -29,7 +29,7 @@ exports.fn = function (item) { inheritableAttrs.includes(name) === false && presentationNonInheritableGroupAttrs.includes(name) === false ) { - item.removeAttr(name); + delete item.attributes[name]; } } } diff --git a/plugins/removeUnknownsAndDefaults.js b/plugins/removeUnknownsAndDefaults.js index c26b9ce1..e97d5540 100644 --- a/plugins/removeUnknownsAndDefaults.js +++ b/plugins/removeUnknownsAndDefaults.js @@ -107,19 +107,19 @@ exports.fn = function (item, params) { (params.unknownAttrs && elems[elem].attrs.indexOf(name) === -1) || // attrs with default values (params.defaultAttrs && - !item.hasAttr('id') && + item.attributes.id == null && elems[elem].defaults && elems[elem].defaults[name] === value && - (attrsInheritable.indexOf(name) < 0 || + (attrsInheritable.includes(name) === false || !item.parentNode.computedAttr(name))) || // useless overrides (params.uselessOverrides && - !item.hasAttr('id') && - applyGroups.indexOf(name) < 0 && - attrsInheritable.indexOf(name) > -1 && + item.attributes.id == null && + applyGroups.includes(name) === false && + attrsInheritable.includes(name) === true && item.parentNode.computedAttr(name, value)) ) { - item.removeAttr(name); + delete item.attributes[name]; } } } diff --git a/plugins/removeUnusedNS.js b/plugins/removeUnusedNS.js index 0b38ec76..cbe598b2 100644 --- a/plugins/removeUnusedNS.js +++ b/plugins/removeUnusedNS.js @@ -17,8 +17,8 @@ exports.description = 'removes unused namespaces declaration'; * @author Kir Belevich */ exports.fn = function (data) { - var svgElem, - xmlnsCollection = []; + let svgElem; + const xmlnsCollection = []; /** * Remove namespace from collection. @@ -26,7 +26,7 @@ exports.fn = function (data) { * @param {String} ns namescape name */ function removeNSfromCollection(ns) { - var pos = xmlnsCollection.indexOf(ns); + const pos = xmlnsCollection.indexOf(ns); // if found - remove ns from the namespaces collection if (pos > -1) { @@ -89,7 +89,7 @@ exports.fn = function (data) { // remove svg element ns-attributes if they are not used even once if (xmlnsCollection.length) { xmlnsCollection.forEach(function (name) { - svgElem.removeAttr('xmlns:' + name); + delete svgElem.attributes['xmlns:' + name]; }); } diff --git a/plugins/removeUselessStrokeAndFill.js b/plugins/removeUselessStrokeAndFill.js index ddc66f0b..8ae9f50a 100644 --- a/plugins/removeUselessStrokeAndFill.js +++ b/plugins/removeUselessStrokeAndFill.js @@ -58,15 +58,13 @@ exports.fn = function (item, params) { for (const name of Object.keys(item.attributes)) { if (regStrokeProps.test(name)) { - item.removeAttr(name); + delete item.attributes[name]; } } - if (declineStroke) - item.addAttr({ - name: 'stroke', - value: 'none', - }); + if (declineStroke) { + item.attributes.stroke = 'none'; + } } } @@ -74,17 +72,12 @@ exports.fn = function (item, params) { if (params.fill && (!fill || item.computedAttr('fill-opacity', '0'))) { for (const name of Object.keys(item.attributes)) { if (regFillProps.test(name)) { - item.removeAttr(name); + delete item.attributes[name]; } } if (fill) { - if (item.hasAttr('fill')) item.attr('fill').value = 'none'; - else - item.addAttr({ - name: 'fill', - value: 'none', - }); + item.attributes.fill = 'none'; } } diff --git a/plugins/removeViewBox.js b/plugins/removeViewBox.js index c062617a..2b9bf74e 100644 --- a/plugins/removeViewBox.js +++ b/plugins/removeViewBox.js @@ -6,7 +6,7 @@ exports.active = true; exports.description = 'removes viewBox attribute when possible'; -var viewBoxElems = ['svg', 'pattern', 'symbol']; +const viewBoxElems = ['svg', 'pattern', 'symbol']; /** * Remove viewBox attr which coincides with a width/height box. @@ -25,25 +25,26 @@ var viewBoxElems = ['svg', 'pattern', 'symbol']; */ exports.fn = function (item) { if ( - item.isElem(viewBoxElems) && - item.hasAttr('viewBox') && - item.hasAttr('width') && - item.hasAttr('height') + item.type === 'element' && + viewBoxElems.includes(item.name) && + item.attributes.viewBox != null && + item.attributes.width != null && + item.attributes.height != null ) { // TODO remove width/height for such case instead - if (item.isElem('svg') && item.closestElem('svg')) { + if (item.name === 'svg' && item.closestElem('svg')) { return; } - var nums = item.attr('viewBox').value.split(/[ ,]+/g); + const nums = item.attributes.viewBox.split(/[ ,]+/g); if ( nums[0] === '0' && nums[1] === '0' && - item.attr('width').value.replace(/px$/, '') === nums[2] && // could use parseFloat too - item.attr('height').value.replace(/px$/, '') === nums[3] + item.attributes.width.replace(/px$/, '') === nums[2] && // could use parseFloat too + item.attributes.height.replace(/px$/, '') === nums[3] ) { - item.removeAttr('viewBox'); + delete item.attributes.viewBox; } } }; diff --git a/plugins/removeXMLNS.js b/plugins/removeXMLNS.js index e2c95408..c4da3ef3 100644 --- a/plugins/removeXMLNS.js +++ b/plugins/removeXMLNS.js @@ -21,7 +21,7 @@ exports.description = * @author Ricardo Tomasi */ exports.fn = function (item) { - if (item.isElem('svg') && item.hasAttr('xmlns')) { - item.removeAttr('xmlns'); + if (item.type === 'element' && item.name === 'svg') { + delete item.attributes.xmlns; } }; diff --git a/plugins/reusePaths.js b/plugins/reusePaths.js index cc80c3ed..016fba66 100644 --- a/plugins/reusePaths.js +++ b/plugins/reusePaths.js @@ -68,11 +68,11 @@ exports.fn = function (data) { const defClone = def.clone(); def.style = style; def.class = defClass; - defClone.removeAttr('transform'); + delete defClone.attributes.transform; defsTag.spliceContent(0, 0, defClone); // Convert the original def to a use so the first usage isn't duplicated. def = convertToUse(def, defClone.attr('id').value); - def.removeAttr('id'); + delete def.attributes.id; } } return data; @@ -81,9 +81,9 @@ exports.fn = function (data) { /** */ function convertToUse(item, href) { item.renameElem('use'); - item.removeAttr('d'); - item.removeAttr('stroke'); - item.removeAttr('fill'); + delete item.attributes.d; + delete item.attributes.stroke; + delete item.attributes.fill; item.addAttr({ name: 'xlink:href', value: '#' + href,