mirror of
https://github.com/svg/svgo.git
synced 2025-07-29 20:21:14 +03:00
Remove prefix/local support in elements and attributes (#1413)
These parts of element and attribute name are easy to extract. Now we can easily replace attrs with xast attributes object.
This commit is contained in:
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}),
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -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)))
|
||||
|
@ -32,8 +32,6 @@ exports.fn = function (item) {
|
||||
item.addAttr({
|
||||
name: 'r',
|
||||
value: radius,
|
||||
prefix: '',
|
||||
local: 'r',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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']);
|
||||
}
|
||||
|
@ -104,8 +104,6 @@ exports.fn = function (item, params) {
|
||||
attrs[prop] = {
|
||||
name: prop,
|
||||
value: val,
|
||||
local: prop,
|
||||
prefix: '',
|
||||
};
|
||||
|
||||
return false;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ exports.fn = function (item) {
|
||||
} else {
|
||||
inner.addAttr({
|
||||
name: attr.name,
|
||||
local: attr.local,
|
||||
prefix: attr.prefix,
|
||||
value: attr.value,
|
||||
});
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
|
||||
// <svg xmlns:sodipodi="">
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
// <sodipodi:*>
|
||||
if (prefixes.indexOf(item.prefix) > -1) {
|
||||
const { prefix } = parseName(item.elem);
|
||||
if (prefixes.includes(prefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
});
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 () {
|
||||
|
@ -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;
|
||||
});
|
||||
|
Reference in New Issue
Block a user