diff --git a/docs/03-plugins/remove-deprecated-attrs.mdx b/docs/03-plugins/remove-deprecated-attrs.mdx
new file mode 100644
index 000000000..28235943e
--- /dev/null
+++ b/docs/03-plugins/remove-deprecated-attrs.mdx
@@ -0,0 +1,21 @@
+---
+title: Remove Deprecated Attributes
+svgo:
+ pluginId: removeDeprecatedAttrs
+---
+
+Remove deprecated attributes from elements in the document.
+
+This plugin does not remove attributes from the deprecated XLink namespace. To remove them, use the [Remove XLink](/docs/plugins/remove-xlink/) plugin.
+
+## Usage
+
+
+
+## Demo
+
+
+
+## Implementation
+
+* https://github.com/svg/svgo/blob/main/plugins/removeDeprecatedAttrs.js
diff --git a/lib/builtin.js b/lib/builtin.js
index 28a380ec9..ce9a43c46 100644
--- a/lib/builtin.js
+++ b/lib/builtin.js
@@ -27,6 +27,7 @@ exports.builtin = [
require('../plugins/removeAttributesBySelector.js'),
require('../plugins/removeAttrs.js'),
require('../plugins/removeComments.js'),
+ require('../plugins/removeDeprecatedAttrs.js'),
require('../plugins/removeDesc.js'),
require('../plugins/removeDimensions.js'),
require('../plugins/removeDoctype.js'),
diff --git a/plugins/_collections.js b/plugins/_collections.js
index b9e67cb7c..b82bc40a4 100644
--- a/plugins/_collections.js
+++ b/plugins/_collections.js
@@ -369,11 +369,30 @@ exports.attrsGroupsDefaults = {
},
};
+/**
+ * @type {Record>}
+ * @see https://www.w3.org/TR/SVG11/intro.html#Definitions
+ */
+exports.attrsGroupsDeprecated = {
+ animationAttributeTarget: ['attributeType'],
+ conditionalProcessing: ['requiredFeatures'],
+ core: ['xml:base', 'xml:lang', 'xml:space'],
+ presentation: [
+ 'clip',
+ 'color-profile',
+ 'enable-background',
+ 'glyph-orientation-horizontal',
+ 'glyph-orientation-vertical',
+ 'kerning',
+ ],
+};
+
/**
* @type {Record,
* attrs?: Array,
* defaults?: Record,
+ * deprecated?: Array,
* contentGroups?: Array,
* content?: Array,
* }>}
@@ -568,6 +587,7 @@ exports.elems = {
name: 'sRGB',
'rendering-intent': 'auto',
},
+ deprecated: ['name'],
contentGroups: ['descriptive'],
},
cursor: {
@@ -937,6 +957,7 @@ exports.elems = {
width: '120%',
height: '120%',
},
+ deprecated: ['filterRes'],
contentGroups: ['descriptive', 'filterPrimitive'],
content: ['animate', 'set'],
},
@@ -957,6 +978,13 @@ exports.elems = {
'horiz-origin-x': '0',
'horiz-origin-y': '0',
},
+ deprecated: [
+ 'horiz-origin-x',
+ 'horiz-origin-y',
+ 'vert-adv-y',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ ],
contentGroups: ['descriptive'],
content: ['font-face', 'glyph', 'hkern', 'missing-glyph', 'vkern'],
},
@@ -1007,6 +1035,29 @@ exports.elems = {
'panose-1': '0 0 0 0 0 0 0 0 0 0',
slope: '0',
},
+ deprecated: [
+ 'accent-height',
+ 'alphabetic',
+ 'ascent',
+ 'bbox',
+ 'cap-height',
+ 'descent',
+ 'hanging',
+ 'ideographic',
+ 'mathematical',
+ 'panose-1',
+ 'slope',
+ 'stemh',
+ 'stemv',
+ 'unicode-range',
+ 'units-per-em',
+ 'v-alphabetic',
+ 'v-hanging',
+ 'v-ideographic',
+ 'v-mathematical',
+ 'widths',
+ 'x-height',
+ ],
contentGroups: ['descriptive'],
content: [
// TODO: "at most one 'font-face-src' element"
@@ -1017,10 +1068,12 @@ exports.elems = {
'font-face-format': {
attrsGroups: ['core'],
attrs: ['string'],
+ deprecated: ['string'],
},
'font-face-name': {
attrsGroups: ['core'],
attrs: ['name'],
+ deprecated: ['name'],
},
'font-face-src': {
attrsGroups: ['core'],
@@ -1108,6 +1161,16 @@ exports.elems = {
defaults: {
'arabic-form': 'initial',
},
+ deprecated: [
+ 'arabic-form',
+ 'glyph-name',
+ 'horiz-adv-x',
+ 'orientation',
+ 'unicode',
+ 'vert-adv-y',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ ],
contentGroups: [
'animation',
'descriptive',
@@ -1147,6 +1210,7 @@ exports.elems = {
'vert-origin-y',
'vert-adv-y',
],
+ deprecated: ['horiz-adv-x', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y'],
contentGroups: [
'animation',
'descriptive',
@@ -1210,6 +1274,7 @@ exports.elems = {
hkern: {
attrsGroups: ['core'],
attrs: ['u1', 'g1', 'u2', 'g2', 'k'],
+ deprecated: ['g1', 'g2', 'k', 'u1', 'u2'],
},
image: {
attrsGroups: [
@@ -1404,6 +1469,7 @@ exports.elems = {
'vert-origin-y',
'vert-adv-y',
],
+ deprecated: ['horiz-adv-x', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y'],
contentGroups: [
'animation',
'descriptive',
@@ -1679,6 +1745,13 @@ exports.elems = {
contentScriptType: 'application/ecmascript',
contentStyleType: 'text/css',
},
+ deprecated: [
+ 'baseProfile',
+ 'contentScriptType',
+ 'contentStyleType',
+ 'version',
+ 'zoomAndPan',
+ ],
contentGroups: [
'animation',
'descriptive',
@@ -1920,11 +1993,13 @@ exports.elems = {
'zoomAndPan',
'viewTarget',
],
+ deprecated: ['viewTarget', 'zoomAndPan'],
contentGroups: ['descriptive'],
},
vkern: {
attrsGroups: ['core'],
attrs: ['u1', 'g1', 'u2', 'g2', 'k'],
+ deprecated: ['g1', 'g2', 'k', 'u1', 'u2'],
},
};
diff --git a/plugins/plugins-types.d.ts b/plugins/plugins-types.d.ts
index 7cd56706a..9f2b7e25c 100644
--- a/plugins/plugins-types.d.ts
+++ b/plugins/plugins-types.d.ts
@@ -141,6 +141,7 @@ type DefaultPlugins = {
removeComments: {
preservePatterns: Array | false;
};
+ removeDeprecatedAttrs: void;
removeDesc: {
removeAny?: boolean;
};
diff --git a/plugins/removeDeprecatedAttrs.js b/plugins/removeDeprecatedAttrs.js
new file mode 100644
index 000000000..9eb5f636d
--- /dev/null
+++ b/plugins/removeDeprecatedAttrs.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const { attrsGroupsDeprecated, elems } = require('./_collections');
+
+exports.name = 'removeDeprecatedAttrs';
+exports.description = 'removes deprecated attributes';
+
+/**
+ * Remove deprecated attributes.
+ *
+ * @type {import('./plugins-types').Plugin<'removeDeprecatedAttrs'>}
+ */
+exports.fn = () => {
+ return {
+ element: {
+ enter: (node) => {
+ const elemConfig = elems[node.name];
+ if (!elemConfig) {
+ return;
+ }
+
+ elemConfig.attrsGroups.forEach((attrsGroup) => {
+ const deprecated = attrsGroupsDeprecated[attrsGroup];
+ if (!deprecated) {
+ return;
+ }
+
+ deprecated.forEach((name) => {
+ delete node.attributes[name];
+ });
+ });
+
+ const deprecated = elemConfig.deprecated;
+ if (!deprecated) {
+ return;
+ }
+
+ deprecated.forEach((name) => {
+ delete node.attributes[name];
+ });
+ },
+ },
+ };
+};
diff --git a/test/plugins/_collections.test.js b/test/plugins/_collections.test.js
new file mode 100644
index 000000000..e9a018c07
--- /dev/null
+++ b/test/plugins/_collections.test.js
@@ -0,0 +1,16 @@
+const { elems } = require('../../plugins/_collections');
+
+describe('elems.deprecated', () => {
+ Object.entries(elems).forEach(([tagName, elemConfig]) => {
+ const deprecated = elemConfig.deprecated;
+ if (!deprecated) {
+ return;
+ }
+
+ test(`${tagName} deprecated attributes are all known attributes`, () => {
+ deprecated.forEach((attr) => {
+ expect(elemConfig.attrs).toContain(attr);
+ });
+ });
+ });
+});
diff --git a/test/plugins/removeDeprecatedAttrs.01.svg b/test/plugins/removeDeprecatedAttrs.01.svg
new file mode 100644
index 000000000..cd2d1c6b6
--- /dev/null
+++ b/test/plugins/removeDeprecatedAttrs.01.svg
@@ -0,0 +1,13 @@
+Removes deprecated version attribute from svg node.
+
+===
+
+
+
+@@@
+
+
diff --git a/test/plugins/removeDeprecatedAttrs.02.svg b/test/plugins/removeDeprecatedAttrs.02.svg
new file mode 100644
index 000000000..2604bec0d
--- /dev/null
+++ b/test/plugins/removeDeprecatedAttrs.02.svg
@@ -0,0 +1,13 @@
+Removes deprecated viewTarget attribute from view node.
+
+===
+
+
+
+@@@
+
+
diff --git a/test/plugins/removeDeprecatedAttrs.03.svg b/test/plugins/removeDeprecatedAttrs.03.svg
new file mode 100644
index 000000000..3748e2fdd
--- /dev/null
+++ b/test/plugins/removeDeprecatedAttrs.03.svg
@@ -0,0 +1,23 @@
+Removes deprecated presentation group attribute enable-background.
+
+===
+
+
+
+@@@
+
+