removeEmptyContainers.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. 'use strict';
  2. const { detachNodeFromParent } = require('../lib/xast.js');
  3. const { elemsGroups } = require('./_collections.js');
  4. exports.type = 'visitor';
  5. exports.name = 'removeEmptyContainers';
  6. exports.active = true;
  7. exports.description = 'removes empty container elements';
  8. /**
  9. * Remove empty containers.
  10. *
  11. * @see https://www.w3.org/TR/SVG11/intro.html#TermContainerElement
  12. *
  13. * @example
  14. * <defs/>
  15. *
  16. * @example
  17. * <g><marker><a/></marker></g>
  18. *
  19. * @author Kir Belevich
  20. *
  21. * @type {import('../lib/types').Plugin<void>}
  22. */
  23. exports.fn = () => {
  24. return {
  25. element: {
  26. exit: (node, parentNode) => {
  27. // remove only empty non-svg containers
  28. if (
  29. node.name === 'svg' ||
  30. elemsGroups.container.includes(node.name) === false ||
  31. node.children.length !== 0
  32. ) {
  33. return;
  34. }
  35. // empty patterns may contain reusable configuration
  36. if (
  37. node.name === 'pattern' &&
  38. Object.keys(node.attributes).length !== 0
  39. ) {
  40. return;
  41. }
  42. // The <g> may not have content, but the filter may cause a rectangle
  43. // to be created and filled with pattern.
  44. if (node.name === 'g' && node.attributes.filter != null) {
  45. return;
  46. }
  47. // empty <mask> hides masked element
  48. if (node.name === 'mask' && node.attributes.id != null) {
  49. return;
  50. }
  51. detachNodeFromParent(node, parentNode);
  52. },
  53. },
  54. };
  55. };