removeUselessDefs.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. 'use strict';
  2. /**
  3. * @typedef {import('../lib/types').XastElement} XastElement
  4. */
  5. const { detachNodeFromParent } = require('../lib/xast.js');
  6. const { elemsGroups } = require('./_collections.js');
  7. exports.type = 'visitor';
  8. exports.name = 'removeUselessDefs';
  9. exports.active = true;
  10. exports.description = 'removes elements in <defs> without id';
  11. /**
  12. * Removes content of defs and properties that aren't rendered directly without ids.
  13. *
  14. * @author Lev Solntsev
  15. *
  16. * @type {import('../lib/types').Plugin<void>}
  17. */
  18. exports.fn = () => {
  19. return {
  20. element: {
  21. enter: (node, parentNode) => {
  22. if (node.name === 'defs') {
  23. /**
  24. * @type {Array<XastElement>}
  25. */
  26. const usefulNodes = [];
  27. collectUsefulNodes(node, usefulNodes);
  28. if (usefulNodes.length === 0) {
  29. detachNodeFromParent(node, parentNode);
  30. }
  31. // TODO remove in SVGO 3
  32. for (const usefulNode of usefulNodes) {
  33. // @ts-ignore parentNode is legacy
  34. usefulNode.parentNode = node;
  35. }
  36. node.children = usefulNodes;
  37. } else if (
  38. elemsGroups.nonRendering.includes(node.name) &&
  39. node.attributes.id == null
  40. ) {
  41. detachNodeFromParent(node, parentNode);
  42. }
  43. },
  44. },
  45. };
  46. };
  47. /**
  48. * @type {(node: XastElement, usefulNodes: Array<XastElement>) => void}
  49. */
  50. const collectUsefulNodes = (node, usefulNodes) => {
  51. for (const child of node.children) {
  52. if (child.type === 'element') {
  53. if (child.attributes.id != null || child.name === 'style') {
  54. usefulNodes.push(child);
  55. } else {
  56. collectUsefulNodes(child, usefulNodes);
  57. }
  58. }
  59. }
  60. };