diff --git a/lib/svgo/jsAPI.js b/lib/svgo/jsAPI.js index df9993be..972d2f22 100644 --- a/lib/svgo/jsAPI.js +++ b/lib/svgo/jsAPI.js @@ -1,6 +1,7 @@ 'use strict'; const { selectAll, selectOne, is } = require('css-select'); +const { parseName } = require('./tools.js'); const svgoCssSelectAdapter = require('./css-select-adapter'); var cssSelectOpts = { @@ -81,7 +82,7 @@ JSAPI.prototype.isElem = function (param) { * @return {Object} element */ JSAPI.prototype.renameElem = function (name) { - if (name && typeof name === 'string') this.elem = this.local = name; + if (name && typeof name === 'string') this.elem = name; return this; }; @@ -181,19 +182,23 @@ JSAPI.prototype.hasAttrLocal = function (localName, val) { return this.someAttr(callback); function nameTest(attr) { - return attr.local === localName; + const { local } = parseName(attr.name); + return local === localName; } function stringValueTest(attr) { - return attr.local === localName && val == attr.value; + const { local } = parseName(attr.name); + return local === localName && val == attr.value; } function regexpValueTest(attr) { - return attr.local === localName && val.test(attr.value); + const { local } = parseName(attr.name); + return local === localName && val.test(attr.value); } function funcValueTest(attr) { - return attr.local === localName && val(attr.value); + const { local } = parseName(attr.name); + return local === localName && val(attr.value); } }; @@ -271,12 +276,7 @@ JSAPI.prototype.removeAttr = function (name, val, recursive) { JSAPI.prototype.addAttr = function (attr) { attr = attr || {}; - if ( - attr.name === undefined || - attr.prefix === undefined || - attr.local === undefined - ) - return false; + if (attr.name === undefined) return false; this.attrs = this.attrs || {}; this.attrs[attr.name] = attr; diff --git a/lib/svgo/svg2js.js b/lib/svgo/svg2js.js index 17cf8e15..bc5a4143 100644 --- a/lib/svgo/svg2js.js +++ b/lib/svgo/svg2js.js @@ -73,8 +73,6 @@ module.exports = function (data) { sax.onopentag = function (data) { var elem = { elem: data.name, - prefix: data.prefix, - local: data.local, attrs: {}, }; @@ -96,8 +94,6 @@ module.exports = function (data) { elem.attrs[name] = { name: name, value: attr.value, - prefix: attr.prefix, - local: attr.local, }; } } diff --git a/lib/svgo/tools.js b/lib/svgo/tools.js index f52e9c81..babd3f97 100644 --- a/lib/svgo/tools.js +++ b/lib/svgo/tools.js @@ -138,3 +138,30 @@ var removeLeadingZero = function (num) { return strNum; }; exports.removeLeadingZero = removeLeadingZero; + +const parseName = (name) => { + if (name == null) { + return { + prefix: '', + local: '', + }; + } + if (name === 'xmlns') { + return { + prefix: 'xmlns', + local: '', + }; + } + const chunks = name.split(':'); + if (chunks.length === 1) { + return { + prefix: '', + local: chunks[0], + }; + } + return { + prefix: chunks[0], + local: chunks[1], + }; +}; +exports.parseName = parseName; diff --git a/plugins/_path.js b/plugins/_path.js index ff8764c7..27d29ae1 100644 --- a/plugins/_path.js +++ b/plugins/_path.js @@ -172,8 +172,6 @@ exports.applyTransforms = function (elem, path, params) { } else { elem.addAttr({ name: 'stroke-width', - prefix: '', - local: 'stroke-width', value: strokeWidth.replace(regNumericValues, function (num) { return removeLeadingZero(num * scale); }), diff --git a/plugins/addAttributesToSVGElement.js b/plugins/addAttributesToSVGElement.js index db846dc0..2a3ab0a8 100644 --- a/plugins/addAttributesToSVGElement.js +++ b/plugins/addAttributesToSVGElement.js @@ -65,8 +65,6 @@ exports.fn = function (data, params) { if (!svg.hasAttr(attribute)) { svg.addAttr({ name: attribute, - prefix: '', - local: attribute, }); } } else if (typeof attribute === 'object') { @@ -75,8 +73,6 @@ exports.fn = function (data, params) { svg.addAttr({ name: key, value: attribute[key], - prefix: '', - local: key, }); } }); diff --git a/plugins/cleanupIDs.js b/plugins/cleanupIDs.js index 0276ebde..e840566a 100644 --- a/plugins/cleanupIDs.js +++ b/plugins/cleanupIDs.js @@ -1,5 +1,7 @@ 'use strict'; +const { parseName } = require('../lib/svgo/tools.js'); + exports.type = 'full'; exports.active = true; @@ -157,13 +159,14 @@ exports.fn = function (data, params) { return; } // save references + const { local } = parseName(attr.name); if ( referencesProps.has(attr.name) && (match = attr.value.match(regReferencesUrl)) ) { key = match[2]; // url() reference } else if ( - (attr.local === 'href' && + (local === 'href' && (match = attr.value.match(regReferencesHref))) || (attr.name === 'begin' && (match = attr.value.match(regReferencesBegin))) diff --git a/plugins/convertEllipseToCircle.js b/plugins/convertEllipseToCircle.js index 85e09ccd..b08f2527 100644 --- a/plugins/convertEllipseToCircle.js +++ b/plugins/convertEllipseToCircle.js @@ -32,8 +32,6 @@ exports.fn = function (item) { item.addAttr({ name: 'r', value: radius, - prefix: '', - local: 'r', }); } } diff --git a/plugins/convertShapeToPath.js b/plugins/convertShapeToPath.js index 4036b980..3b861b90 100644 --- a/plugins/convertShapeToPath.js +++ b/plugins/convertShapeToPath.js @@ -58,8 +58,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'd', value: stringifyPathData({ pathData, precision }), - prefix: '', - local: 'd', }); item.renameElem('path').removeAttr(['x', 'y', 'width', 'height']); } @@ -77,8 +75,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'd', value: stringifyPathData({ pathData, precision }), - prefix: '', - local: 'd', }); item.renameElem('path').removeAttr(['x1', 'y1', 'x2', 'y2']); } @@ -102,8 +98,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'd', value: stringifyPathData({ pathData, precision }), - prefix: '', - local: 'd', }); item.renameElem('path').removeAttr('points'); } @@ -124,8 +118,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'd', value: stringifyPathData({ pathData, precision }), - prefix: '', - local: 'd', }); item.renameElem('path').removeAttr(['cx', 'cy', 'r']); } @@ -147,8 +139,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'd', value: stringifyPathData({ pathData, precision }), - prefix: '', - local: 'd', }); item.renameElem('path').removeAttr(['cx', 'cy', 'rx', 'ry']); } diff --git a/plugins/convertStyleToAttrs.js b/plugins/convertStyleToAttrs.js index 15398059..2de7cbbf 100644 --- a/plugins/convertStyleToAttrs.js +++ b/plugins/convertStyleToAttrs.js @@ -104,8 +104,6 @@ exports.fn = function (item, params) { attrs[prop] = { name: prop, value: val, - local: prop, - prefix: '', }; return false; diff --git a/plugins/moveElemsAttrsToGroup.js b/plugins/moveElemsAttrsToGroup.js index 77e9b3db..45da7fd2 100644 --- a/plugins/moveElemsAttrsToGroup.js +++ b/plugins/moveElemsAttrsToGroup.js @@ -100,9 +100,7 @@ function intersectInheritableAttrs(a, b) { b.hasOwnProperty(n) && inheritableAttrs.indexOf(n) > -1 && attr.name === b[n].name && - attr.value === b[n].value && - attr.prefix === b[n].prefix && - attr.local === b[n].local + attr.value === b[n].value ) { c[n] = attr; } diff --git a/plugins/moveGroupAttrsToElems.js b/plugins/moveGroupAttrsToElems.js index 36027448..63e9dc1b 100644 --- a/plugins/moveGroupAttrsToElems.js +++ b/plugins/moveGroupAttrsToElems.js @@ -50,8 +50,6 @@ exports.fn = function (item) { } else { inner.addAttr({ name: attr.name, - local: attr.local, - prefix: attr.prefix, value: attr.value, }); } diff --git a/plugins/removeDimensions.js b/plugins/removeDimensions.js index f37e3a4e..292add9b 100644 --- a/plugins/removeDimensions.js +++ b/plugins/removeDimensions.js @@ -38,8 +38,6 @@ exports.fn = function (item) { Number(item.attr('width').value) + ' ' + Number(item.attr('height').value), - prefix: '', - local: 'viewBox', }); item.removeAttr('width'); item.removeAttr('height'); diff --git a/plugins/removeEditorsNSData.js b/plugins/removeEditorsNSData.js index 050deafb..cb964f90 100644 --- a/plugins/removeEditorsNSData.js +++ b/plugins/removeEditorsNSData.js @@ -1,5 +1,7 @@ 'use strict'; +const { parseName } = require('../lib/svgo/tools.js'); + exports.type = 'perItem'; exports.active = true; @@ -35,11 +37,9 @@ exports.fn = function (item, params) { if (item.elem) { if (item.isElem('svg')) { item.eachAttr(function (attr) { - if ( - attr.prefix === 'xmlns' && - editorNamespaces.indexOf(attr.value) > -1 - ) { - prefixes.push(attr.local); + const { prefix, local } = parseName(attr.name); + if (prefix === 'xmlns' && editorNamespaces.includes(attr.value)) { + prefixes.push(local); // item.removeAttr(attr.name); @@ -49,13 +49,15 @@ exports.fn = function (item, params) { // <* sodipodi:*=""> item.eachAttr(function (attr) { - if (prefixes.indexOf(attr.prefix) > -1) { + const { prefix } = parseName(attr.name); + if (prefixes.includes(prefix)) { item.removeAttr(attr.name); } }); // - if (prefixes.indexOf(item.prefix) > -1) { + const { prefix } = parseName(item.elem); + if (prefixes.includes(prefix)) { return false; } } diff --git a/plugins/removeOffCanvasPaths.js b/plugins/removeOffCanvasPaths.js index 7e131882..2b0c4f89 100644 --- a/plugins/removeOffCanvasPaths.js +++ b/plugins/removeOffCanvasPaths.js @@ -103,13 +103,9 @@ function parseViewBox(svg) { var path = new JSAPI({ elem: 'path', - prefix: '', - local: 'path', }); path.addAttr({ name: 'd', - prefix: '', - local: 'd', value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z', }); diff --git a/plugins/removeUnknownsAndDefaults.js b/plugins/removeUnknownsAndDefaults.js index 260d79b5..300eb2de 100644 --- a/plugins/removeUnknownsAndDefaults.js +++ b/plugins/removeUnknownsAndDefaults.js @@ -1,5 +1,7 @@ 'use strict'; +const { parseName } = require('../lib/svgo/tools.js'); + exports.type = 'perItem'; exports.active = true; @@ -66,7 +68,7 @@ for (const elem of Object.values(elems)) { */ exports.fn = function (item, params) { // elems w/o namespace prefix - if (item.isElem() && !item.prefix) { + if (item.isElem() && !parseName(item.elem).prefix) { var elem = item.elem; // remove unknown element's content @@ -79,7 +81,7 @@ exports.fn = function (item, params) { item.content.forEach(function (content, i) { if ( content.isElem() && - !content.prefix && + !parseName(content.elem).prefix && ((elems[elem].content && // Do we have a record of its permitted content? elems[elem].content.indexOf(content.elem) === -1) || (!elems[elem].content && // we dont know about its permitted content @@ -93,9 +95,10 @@ exports.fn = function (item, params) { // remove element's unknown attrs and attrs with default values if (elems[elem] && elems[elem].attrs) { item.eachAttr(function (attr) { + const { prefix } = parseName(attr.name); if ( attr.name !== 'xmlns' && - (attr.prefix === 'xml' || !attr.prefix) && + (prefix === 'xml' || !prefix) && (!params.keepDataAttrs || attr.name.indexOf('data-') != 0) && (!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) && (!params.keepRoleAttr || attr.name != 'role') diff --git a/plugins/removeUnusedNS.js b/plugins/removeUnusedNS.js index 1639d4a7..9f3d1bbe 100644 --- a/plugins/removeUnusedNS.js +++ b/plugins/removeUnusedNS.js @@ -1,5 +1,7 @@ 'use strict'; +const { parseName } = require('../lib/svgo/tools.js'); + exports.type = 'full'; exports.active = true; @@ -48,9 +50,10 @@ exports.fn = function (data) { if (item.isElem('svg')) { item.eachAttr(function (attr) { + const { prefix, local } = parseName(attr.name); // collect namespaces - if (attr.prefix === 'xmlns' && attr.local) { - xmlnsCollection.push(attr.local); + if (prefix === 'xmlns' && local) { + xmlnsCollection.push(local); } }); @@ -62,14 +65,16 @@ exports.fn = function (data) { } if (xmlnsCollection.length) { + const { prefix } = parseName(item.elem); // check item for the ns-attrs - if (item.prefix) { - removeNSfromCollection(item.prefix); + if (prefix) { + removeNSfromCollection(prefix); } // check each attr for the ns-attrs item.eachAttr(function (attr) { - removeNSfromCollection(attr.prefix); + const { prefix } = parseName(attr.name); + removeNSfromCollection(prefix); }); } diff --git a/plugins/removeUselessStrokeAndFill.js b/plugins/removeUselessStrokeAndFill.js index 555aa5fc..09fb5043 100644 --- a/plugins/removeUselessStrokeAndFill.js +++ b/plugins/removeUselessStrokeAndFill.js @@ -66,8 +66,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'stroke', value: 'none', - prefix: '', - local: 'stroke', }); } } @@ -86,8 +84,6 @@ exports.fn = function (item, params) { item.addAttr({ name: 'fill', value: 'none', - prefix: '', - local: 'fill', }); } } diff --git a/plugins/reusePaths.js b/plugins/reusePaths.js index 243485d5..2dd26cdd 100644 --- a/plugins/reusePaths.js +++ b/plugins/reusePaths.js @@ -39,8 +39,6 @@ exports.fn = function (data) { if (!hasSeen.elem.hasAttr('id')) { hasSeen.elem.addAttr({ name: 'id', - local: 'id', - prefix: '', value: 'reuse-' + count++, }); } @@ -52,8 +50,6 @@ exports.fn = function (data) { const defsTag = new JSAPI( { elem: 'defs', - prefix: '', - local: 'defs', content: [], attrs: [], }, @@ -89,8 +85,6 @@ function convertToUse(item, href) { item.removeAttr('fill'); item.addAttr({ name: 'xlink:href', - local: 'xlink:href', - prefix: 'none', value: '#' + href, }); delete item.pathJS; diff --git a/plugins/sortAttrs.js b/plugins/sortAttrs.js index 56093ded..9df6f459 100644 --- a/plugins/sortAttrs.js +++ b/plugins/sortAttrs.js @@ -1,5 +1,7 @@ 'use strict'; +const { parseName } = require('../lib/svgo/tools.js'); + exports.type = 'perItem'; exports.active = false; @@ -48,13 +50,15 @@ exports.fn = function (item, params) { }); attrs.sort(function (a, b) { - if (a.prefix != b.prefix) { + const { prefix: prefixA } = parseName(a.name); + const { prefix: prefixB } = parseName(b.name); + if (prefixA != prefixB) { // xmlns attributes implicitly have the prefix xmlns if (xmlnsOrder == 'front') { - if (a.prefix == 'xmlns') return -1; - if (b.prefix == 'xmlns') return 1; + if (prefixA === 'xmlns') return -1; + if (prefixB === 'xmlns') return 1; } - return a.prefix < b.prefix ? -1 : 1; + return prefixA < prefixB ? -1 : 1; } var aindex = orderlen; diff --git a/test/jsapi/_index.js b/test/jsapi/_index.js index 6790ea2a..159d9372 100644 --- a/test/jsapi/_index.js +++ b/test/jsapi/_index.js @@ -12,13 +12,9 @@ describe('svgo api', function () { it('should be able to create content item', function () { var item = createContentItem({ elem: 'elementName', - prefix: 'prefixName', - local: 'localName', }); expect(item).to.be.instanceOf(JSAPI); expect(item).to.have.ownProperty('elem').equal('elementName'); - expect(item).to.have.ownProperty('prefix').equal('prefixName'); - expect(item).to.have.ownProperty('local').equal('localName'); }); it('should be able create content item without argument', function () { diff --git a/test/svg2js/_index.js b/test/svg2js/_index.js index 6268838f..86cc7211 100644 --- a/test/svg2js/_index.js +++ b/test/svg2js/_index.js @@ -103,14 +103,6 @@ describe('svg2js', function () { it('should have property elem: "svg"', function () { expect(root.content[3]).to.have.property('elem', 'svg'); }); - - it('should have property prefix: ""', function () { - expect(root.content[3]).to.have.property('prefix', ''); - }); - - it('should have property local: "svg"', function () { - expect(root.content[3]).to.have.property('local', 'svg'); - }); }); describe('attributes', function () { @@ -146,17 +138,6 @@ describe('svg2js', function () { '1.1' ); }); - - it('should have property prefix: ""', function () { - expect(root.content[3].attrs.version).to.have.property('prefix', ''); - }); - - it('should have property local: "version"', function () { - expect(root.content[3].attrs.version).to.have.property( - 'local', - 'version' - ); - }); }); }); @@ -335,8 +316,6 @@ describe('svg2js', function () { var attr = { name: 'test', value: 3, - prefix: '', - local: 'test', }; it('svg should have property "addAttr"', function () { @@ -353,31 +332,6 @@ describe('svg2js', function () { ).to.be.an.instanceOf(Object); }); - it('svg.addAttr({ name: "trololo" }) should be false', function () { - expect(root.content[3].addAttr({ name: 'trololo' })).to.be.false; - }); - - it('svg.addAttr({ name: "trololo", value: 3 }) should be false', function () { - expect(root.content[3].addAttr({ name: 'trololo', value: 3 })).to.be - .false; - }); - - it('svg.addAttr({ name: "trololo", value: 3, prefix: "" }) should be false', function () { - expect( - root.content[3].addAttr({ name: 'trololo', value: 3, prefix: '' }) - ).to.be.false; - }); - - it('svg.addAttr({ name: "trololo", value: 3, local: "trololo" }) should be false', function () { - expect( - root.content[3].addAttr({ - name: 'trololo', - value: 3, - local: 'trololo', - }) - ).to.be.false; - }); - it('svg.addAttr() should be false', function () { expect(root.content[3].addAttr()).to.be.false; });