| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 | 'use strict';/** * @typedef {import('../lib/types').XastElement} XastElement * @typedef {import('../lib/types').XastParent} XastParent * @typedef {import('../lib/types').XastNode} XastNode */const JSAPI = require('../lib/svgo/jsAPI.js');exports.type = 'visitor';exports.name = 'reusePaths';exports.active = false;exports.description =  'Finds <path> elements with the same d, fill, and ' +  'stroke, and converts them to <use> elements ' +  'referencing a single <path> def.';/** * Finds <path> elements with the same d, fill, and stroke, and converts them to * <use> elements referencing a single <path> def. * * @author Jacob Howcroft * * @type {import('../lib/types').Plugin<void>} */exports.fn = () => {  /**   * @type {Map<string, Array<XastElement>>}   */  const paths = new Map();  return {    element: {      enter: (node) => {        if (node.name === 'path' && node.attributes.d != null) {          const d = node.attributes.d;          const fill = node.attributes.fill || '';          const stroke = node.attributes.stroke || '';          const key = d + ';s:' + stroke + ';f:' + fill;          let list = paths.get(key);          if (list == null) {            list = [];            paths.set(key, list);          }          list.push(node);        }      },      exit: (node, parentNode) => {        if (node.name === 'svg' && parentNode.type === 'root') {          /**           * @type {XastElement}           */          const rawDefs = {            type: 'element',            name: 'defs',            attributes: {},            children: [],          };          /**           * @type {XastElement}           */          const defsTag = new JSAPI(rawDefs, node);          let index = 0;          for (const list of paths.values()) {            if (list.length > 1) {              // add reusable path to defs              /**               * @type {XastElement}               */              const rawPath = {                type: 'element',                name: 'path',                attributes: { ...list[0].attributes },                children: [],              };              delete rawPath.attributes.transform;              let id;              if (rawPath.attributes.id == null) {                id = 'reuse-' + index;                index += 1;                rawPath.attributes.id = id;              } else {                id = rawPath.attributes.id;                delete list[0].attributes.id;              }              /**               * @type {XastElement}               */              const reusablePath = new JSAPI(rawPath, defsTag);              defsTag.children.push(reusablePath);              // convert paths to <use>              for (const pathNode of list) {                pathNode.name = 'use';                pathNode.attributes['xlink:href'] = '#' + id;                delete pathNode.attributes.d;                delete pathNode.attributes.stroke;                delete pathNode.attributes.fill;              }            }          }          if (defsTag.children.length !== 0) {            if (node.attributes['xmlns:xlink'] == null) {              node.attributes['xmlns:xlink'] = 'http://www.w3.org/1999/xlink';            }            node.children.unshift(defsTag);          }        }      },    },  };};
 |