mirror of
https://github.com/svg/svgo.git
synced 2025-07-31 07:44:22 +03:00
Refactor removeUnusedNS plugin (#1559)
- covered with types - migrated to visitor plugin api - dropped traverse utility which is replaced by visitor
This commit is contained in:
20
lib/xast.js
20
lib/xast.js
@ -55,26 +55,6 @@ const closestByName = (node, name) => {
|
|||||||
};
|
};
|
||||||
exports.closestByName = closestByName;
|
exports.closestByName = closestByName;
|
||||||
|
|
||||||
const traverseBreak = Symbol();
|
|
||||||
exports.traverseBreak = traverseBreak;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {(node: any, fn: any) => any}
|
|
||||||
*/
|
|
||||||
const traverse = (node, fn) => {
|
|
||||||
if (fn(node) === traverseBreak) {
|
|
||||||
return traverseBreak;
|
|
||||||
}
|
|
||||||
if (node.type === 'root' || node.type === 'element') {
|
|
||||||
for (const child of node.children) {
|
|
||||||
if (traverse(child, fn) === traverseBreak) {
|
|
||||||
return traverseBreak;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
exports.traverse = traverse;
|
|
||||||
|
|
||||||
const visitSkip = Symbol();
|
const visitSkip = Symbol();
|
||||||
exports.visitSkip = visitSkip;
|
exports.visitSkip = visitSkip;
|
||||||
|
|
||||||
|
@ -1,82 +1,61 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { traverse } = require('../lib/xast.js');
|
exports.type = 'visitor';
|
||||||
const { parseName } = require('../lib/svgo/tools.js');
|
|
||||||
|
|
||||||
exports.name = 'removeUnusedNS';
|
exports.name = 'removeUnusedNS';
|
||||||
|
|
||||||
exports.type = 'full';
|
|
||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'removes unused namespaces declaration';
|
exports.description = 'removes unused namespaces declaration';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove unused namespaces declaration.
|
* Remove unused namespaces declaration from svg element
|
||||||
*
|
* which are not used in elements or attributes
|
||||||
* @param {Object} item current iteration item
|
|
||||||
* @return {Boolean} if false, item will be filtered out
|
|
||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
|
||||||
exports.fn = function (root) {
|
|
||||||
let svgElem;
|
|
||||||
const xmlnsCollection = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove namespace from collection.
|
|
||||||
*
|
*
|
||||||
* @param {String} ns namescape name
|
* @type {import('../lib/types').Plugin<void>}
|
||||||
*/
|
*/
|
||||||
function removeNSfromCollection(ns) {
|
exports.fn = () => {
|
||||||
const pos = xmlnsCollection.indexOf(ns);
|
/**
|
||||||
|
* @type {Set<string>}
|
||||||
// if found - remove ns from the namespaces collection
|
*/
|
||||||
if (pos > -1) {
|
const unusedNamespaces = new Set();
|
||||||
xmlnsCollection.splice(pos, 1);
|
return {
|
||||||
}
|
element: {
|
||||||
}
|
enter: (node, parentNode) => {
|
||||||
|
// collect all namespaces from svg element
|
||||||
traverse(root, (node) => {
|
// (such as xmlns:xlink="http://www.w3.org/1999/xlink")
|
||||||
if (node.type === 'element') {
|
if (node.name === 'svg' && parentNode.type === 'root') {
|
||||||
if (node.name === 'svg') {
|
|
||||||
for (const name of Object.keys(node.attributes)) {
|
for (const name of Object.keys(node.attributes)) {
|
||||||
const { prefix, local } = parseName(name);
|
if (name.startsWith('xmlns:')) {
|
||||||
// collect namespaces
|
const local = name.slice('xmlns:'.length);
|
||||||
if (prefix === 'xmlns' && local) {
|
unusedNamespaces.add(local);
|
||||||
xmlnsCollection.push(local);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// if svg element has ns-attr
|
if (unusedNamespaces.size !== 0) {
|
||||||
if (xmlnsCollection.length) {
|
// preserve namespace used in nested elements names
|
||||||
// save svg element
|
if (node.name.includes(':')) {
|
||||||
svgElem = node;
|
const [ns] = node.name.split(':');
|
||||||
|
if (unusedNamespaces.has(ns)) {
|
||||||
|
unusedNamespaces.delete(ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// preserve namespace used in nested elements attributes
|
||||||
if (xmlnsCollection.length) {
|
|
||||||
const { prefix } = parseName(node.name);
|
|
||||||
// check node for the ns-attrs
|
|
||||||
if (prefix) {
|
|
||||||
removeNSfromCollection(prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check each attr for the ns-attrs
|
|
||||||
for (const name of Object.keys(node.attributes)) {
|
for (const name of Object.keys(node.attributes)) {
|
||||||
const { prefix } = parseName(name);
|
if (name.includes(':')) {
|
||||||
removeNSfromCollection(prefix);
|
const [ns] = name.split(':');
|
||||||
|
unusedNamespaces.delete(ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
exit: (node, parentNode) => {
|
||||||
// remove svg element ns-attributes if they are not used even once
|
// remove unused namespace attributes from svg element
|
||||||
if (xmlnsCollection.length) {
|
if (node.name === 'svg' && parentNode.type === 'root') {
|
||||||
for (const name of xmlnsCollection) {
|
for (const name of unusedNamespaces) {
|
||||||
delete svgElem.attributes['xmlns:' + name];
|
delete node.attributes[`xmlns:${name}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
return root;
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
"plugins/removeDimensions.js",
|
"plugins/removeDimensions.js",
|
||||||
"plugins/removeEmptyAttrs.js",
|
"plugins/removeEmptyAttrs.js",
|
||||||
"plugins/removeNonInheritableGroupAttrs.js",
|
"plugins/removeNonInheritableGroupAttrs.js",
|
||||||
"plugins/removeUnusedNS.js",
|
|
||||||
"plugins/removeXMLNS.js",
|
"plugins/removeXMLNS.js",
|
||||||
"plugins/sortAttrs.js",
|
"plugins/sortAttrs.js",
|
||||||
"plugins/removeEmptyContainers.js",
|
"plugins/removeEmptyContainers.js",
|
||||||
|
Reference in New Issue
Block a user