11import { elemsGroups } from './_collections.js' ;
22import { detachNodeFromParent } from '../lib/xast.js' ;
33import { collectStylesheet , computeStyle } from '../lib/style.js' ;
4+ import { findReferences } from '../lib/svgo/tools.js' ;
45
56export const name = 'removeEmptyContainers' ;
67export const description = 'removes empty container elements' ;
@@ -22,9 +23,33 @@ export const description = 'removes empty container elements';
2223 */
2324export const fn = ( root ) => {
2425 const stylesheet = collectStylesheet ( root ) ;
26+ const removedIds = new Set ( ) ;
27+ /**
28+ * @type {Map<string, {
29+ * node: import('../lib/types.js').XastElement,
30+ * parent: import('../lib/types.js').XastParent,
31+ * }[]>}
32+ */
33+ const usesById = new Map ( ) ;
2534
2635 return {
2736 element : {
37+ enter : ( node , parentNode ) => {
38+ if ( node . name === 'use' ) {
39+ // Record uses so those referencing empty containers can be removed.
40+ for ( const [ name , value ] of Object . entries ( node . attributes ) ) {
41+ const ids = findReferences ( name , value ) ;
42+ for ( const id of ids ) {
43+ let references = usesById . get ( id ) ;
44+ if ( references === undefined ) {
45+ references = [ ] ;
46+ usesById . set ( id , references ) ;
47+ }
48+ references . push ( { node : node , parent : parentNode } ) ;
49+ }
50+ }
51+ }
52+ } ,
2853 exit : ( node , parentNode ) => {
2954 // remove only empty non-svg containers
3055 if (
@@ -61,6 +86,22 @@ export const fn = (root) => {
6186 }
6287
6388 detachNodeFromParent ( node , parentNode ) ;
89+ if ( node . attributes . id ) {
90+ removedIds . add ( node . attributes . id ) ;
91+ }
92+ } ,
93+ } ,
94+ root : {
95+ exit : ( ) => {
96+ // Remove any <use> elements that referenced an empty container.
97+ for ( const id of removedIds ) {
98+ const uses = usesById . get ( id ) ;
99+ if ( uses ) {
100+ for ( const use of uses ) {
101+ detachNodeFromParent ( use . node , use . parent ) ;
102+ }
103+ }
104+ }
64105 } ,
65106 } ,
66107 } ;
0 commit comments