Repository: svg/svgo
Pull request #828 (2017-11-02 15:45:33)

Fix matchedOnlyOnce cleaning up classes/IDs despite matching more than once
Fixes https://github.com/svg/svgo/issues/825.


Patch:
diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js
index d3fe62f..25e8dd9 100644
--- a/plugins/inlineStyles.js
+++ b/plugins/inlineStyles.js
@@ -164,34 +164,42 @@ exports.fn = function(document, opts) {
     }
 
 
-    if (opts.removeMatchedSelectors) {
-        // clean up matched class + ID attribute values
-        for (selector of sortedSelectors) {
-            if(!selector.selectedEls) {
-                continue;
-            }
+    if (!opts.removeMatchedSelectors) {
+        return document; // no further processing required
+    }
 
-            for (selectedEl of selector.selectedEls) {
-                // class
-                var firstSubSelector = selector.item.data.children.first();
-                if(firstSubSelector.type === 'ClassSelector') {
-                    selectedEl.class.remove(firstSubSelector.name);
-                }
-                // clean up now empty class attributes
-                if(typeof selectedEl.class.item(0) === 'undefined') {
-                    selectedEl.removeAttr('class');
-                }
 
-                // ID
-                if(firstSubSelector.type === 'IdSelector') {
-                    selectedEl.removeAttr('id', firstSubSelector.name);
-                }
+    // clean up matched class + ID attribute values
+    for (selector of sortedSelectors) {
+        if(!selector.selectedEls) {
+            continue;
+        }
+
+        if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) {
+            // skip selectors that match more than once if option onlyMatchedOnce is enabled
+            continue;
+        }
+
+        for (selectedEl of selector.selectedEls) {
+            // class
+            var firstSubSelector = selector.item.data.children.first();
+            if(firstSubSelector.type === 'ClassSelector') {
+                selectedEl.class.remove(firstSubSelector.name);
+            }
+            // clean up now empty class attributes
+            if(typeof selectedEl.class.item(0) === 'undefined') {
+                selectedEl.removeAttr('class');
+            }
+
+            // ID
+            if(firstSubSelector.type === 'IdSelector') {
+                selectedEl.removeAttr('id', firstSubSelector.name);
             }
         }
     }
 
 
-    // clean up elements
+    // clean up now empty elements
     for (var style of styles) {
         csstree.walkRules(style.cssAst, function(node, item, list) {
             // clean up <style/> atrules without any rulesets left


Test patch:
diff --git a/test/plugins/inlineStyles.18.svg b/test/plugins/inlineStyles.18.svg
new file mode 100644
index 0000000..74b5401
--- /dev/null
+++ b/test/plugins/inlineStyles.18.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#D1DAE5;}
+</style>
+<g>
+	<path class="st0" d="M16.9,12.3c0-0.1,0.1-0.2,0.1-0.3c0,0,0-0.1,0-0.1c0-0.1,0-0.2,0-0.2c0,0,0,0,0,0c0-0.1-0.1-0.2-0.2-0.3
+		c0,0,0-0.1,0-0.1c0,0,0,0,0,0c0,0,0,0,0,0l-3.5-3.5c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l1.8,1.8H7.5c-0.6,0-1,0.4-1,1s0.4,1,1,1h6.1
+		l-1.9,1.9c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3l3.6-3.6c0,0,0,0,0,0c0.1-0.1,0.2-0.2,0.2-0.3
+		c0,0,0,0,0,0C16.9,12.3,16.9,12.3,16.9,12.3z"/>
+	<path class="st0" d="M12,0C5.4,0,0,5.4,0,12s5.4,12,12,12s12-5.4,12-12S18.6,0,12,0z M12,22C6.5,22,2,17.5,2,12S6.5,2,12,2
+		s10,4.5,10,10S17.5,22,12,22z"/>
+</g>
+</svg>
+
+@@@
+
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)-->
+<svg version="1.1" id="Logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24" xml:space="preserve">
+    <style type="text/css">
+        .st0{fill:#D1DAE5}
+    </style>
+    <g>
+        <path class="st0" d="M16.9,12.3c0-0.1,0.1-0.2,0.1-0.3c0,0,0-0.1,0-0.1c0-0.1,0-0.2,0-0.2c0,0,0,0,0,0c0-0.1-0.1-0.2-0.2-0.3
+		c0,0,0-0.1,0-0.1c0,0,0,0,0,0c0,0,0,0,0,0l-3.5-3.5c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l1.8,1.8H7.5c-0.6,0-1,0.4-1,1s0.4,1,1,1h6.1
+		l-1.9,1.9c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3l3.6-3.6c0,0,0,0,0,0c0.1-0.1,0.2-0.2,0.2-0.3
+		c0,0,0,0,0,0C16.9,12.3,16.9,12.3,16.9,12.3z"/>
+        <path class="st0" d="M12,0C5.4,0,0,5.4,0,12s5.4,12,12,12s12-5.4,12-12S18.6,0,12,0z M12,22C6.5,22,2,17.5,2,12S6.5,2,12,2
+		s10,4.5,10,10S17.5,22,12,22z"/>
+    </g>
+</svg>
+
+@@@
+
+{"onlyMatchedOnce":true}
diff --git a/test/plugins/inlineStyles.19.svg b/test/plugins/inlineStyles.19.svg
new file mode 100644
index 0000000..2d7e429
--- /dev/null
+++ b/test/plugins/inlineStyles.19.svg
@@ -0,0 +1,56 @@
+<svg id="icon_time" data-name="icon time" xmlns="http://www.w3.org/2000/svg" width="51" height="51" viewBox="0 0 51 51">
+  <defs>
+    <style>
+      .cls-1, .cls-2, .cls-3 {
+        fill: #f5f5f5;
+        stroke: gray;
+      }
+
+      .cls-1, .cls-2 {
+        stroke-width: 1px;
+      }
+
+      .cls-2 {
+        fill-rule: evenodd;
+      }
+
+      .cls-3 {
+        stroke-width: 2px;
+      }
+    </style>
+  </defs>
+  <circle class="cls-1" cx="25.5" cy="25.5" r="25"/>
+  <g>
+    <path class="cls-2" d="M1098,2415a8,8,0,0,1,8,8v2h-16v-2A8,8,0,0,1,1098,2415Z" transform="translate(-1072.5 -2389.5)"/>
+    <path id="Ellipse_14_copy" data-name="Ellipse 14 copy" class="cls-2" d="M1098,2415a8,8,0,0,0,8-8v-2h-16v2A8,8,0,0,0,1098,2415Z" transform="translate(-1072.5 -2389.5)"/>
+    <path class="cls-2" d="M1089,2427v-1h18v1h-18Z" transform="translate(-1072.5 -2389.5)"/>
+    <path id="Shape_10_copy" data-name="Shape 10 copy" class="cls-2" d="M1089,2404v-1h18v1h-18Z" transform="translate(-1072.5 -2389.5)"/>
+    <circle id="Ellipse_13_copy" data-name="Ellipse 13 copy" class="cls-3" cx="25.5" cy="31.5" r="1"/>
+    <circle id="Ellipse_13_copy_3" data-name="Ellipse 13 copy 3" class="cls-3" cx="28.5" cy="31.5" r="1"/>
+    <circle id="Ellipse_13_copy_2" data-name="Ellipse 13 copy 2" class="cls-3" cx="22.5" cy="31.5" r="1"/>
+  </g>
+</svg>
+
+@@@
+
+<svg id="icon_time" data-name="icon time" xmlns="http://www.w3.org/2000/svg" width="51" height="51" viewBox="0 0 51 51">
+    <defs>
+        <style>
+            .cls-2,.cls-3{fill: #f5f5f5;stroke: gray}.cls-2{stroke-width: 1px}.cls-2{fill-rule: evenodd}.cls-3{stroke-width: 2px}
+        </style>
+    </defs>
+    <circle cx="25.5" cy="25.5" r="25" style="stroke-width:1px;fill:#f5f5f5;stroke:gray"/>
+    <g>
+        <path class="cls-2" d="M1098,2415a8,8,0,0,1,8,8v2h-16v-2A8,8,0,0,1,1098,2415Z" transform="translate(-1072.5 -2389.5)"/>
+        <path id="Ellipse_14_copy" data-name="Ellipse 14 copy" class="cls-2" d="M1098,2415a8,8,0,0,0,8-8v-2h-16v2A8,8,0,0,0,1098,2415Z" transform="translate(-1072.5 -2389.5)"/>
+        <path class="cls-2" d="M1089,2427v-1h18v1h-18Z" transform="translate(-1072.5 -2389.5)"/>
+        <path id="Shape_10_copy" data-name="Shape 10 copy" class="cls-2" d="M1089,2404v-1h18v1h-18Z" transform="translate(-1072.5 -2389.5)"/>
+        <circle id="Ellipse_13_copy" data-name="Ellipse 13 copy" class="cls-3" cx="25.5" cy="31.5" r="1"/>
+        <circle id="Ellipse_13_copy_3" data-name="Ellipse 13 copy 3" class="cls-3" cx="28.5" cy="31.5" r="1"/>
+        <circle id="Ellipse_13_copy_2" data-name="Ellipse 13 copy 2" class="cls-3" cx="22.5" cy="31.5" r="1"/>
+    </g>
+</svg>
+
+@@@
+
+{"onlyMatchedOnce":true}