/* eslint-disable no-cond-assign, default-case */ const escapeForRegexp = require('escape-string-regexp'); const URL_PATTERN = /url\(#([^ ]+?)\s*\)/g; const defaultPattern = '[id]'; /** * @param {string} id * @param {string|Function} pattern */ function renameId(id, pattern) { const result = (typeof pattern === 'function' ? pattern(id) : pattern).toString(); const re = new RegExp(escapeForRegexp('[id]'), 'g'); return result.replace(re, id); } /** * @param {string|Function} [pattern] * @returns {Function} */ function plugin(pattern) { const p = pattern || defaultPattern; return (tree) => { const mappedIds = {}; tree.match({ attrs: { id: /.*/ } }, (node) => { const { attrs } = node; const currentId = attrs.id; const newId = renameId(currentId, p); attrs.id = newId; mappedIds[currentId] = { id: newId, referenced: false, node }; return node; }); tree.match({ tag: /.*/ }, (node) => { const { attrs } = node; if (node.tag === 'style') { while (true) { const content = Array.isArray(node.content) ? node.content.join('') : node.content.toString(); const match = URL_PATTERN.exec(content); if (match === null) { break; } const id = match[1]; if (mappedIds[id]) { mappedIds[id].referenced = true; const re = new RegExp(escapeForRegexp(match[0]), 'g'); node.content = content.replace(re, `url(#${mappedIds[id].id})`); } } } if ('attrs' in node === false) { return node; } Object.keys(attrs).forEach((attrName) => { const value = attrs[attrName]; let id; let match; while ((match = URL_PATTERN.exec(value)) !== null) { id = match[1]; if (mappedIds[id]) { mappedIds[id].referenced = true; const re = new RegExp(escapeForRegexp(match[0]), 'g'); attrs[attrName] = value.replace(re, `url(#${mappedIds[id].id})`); } } let idObj; switch (attrName) { case 'href': case 'xlink:href': if (value.substring(0, 1) !== '#') { break; } id = value.substring(1); idObj = mappedIds[id]; if (idObj) { idObj.referenced = false; attrs[attrName] = `#${idObj.id}`; } break; case 'for': if (node.tag !== 'label') { break; } id = value; idObj = mappedIds[id]; if (idObj) { idObj.referenced = false; attrs[attrName] = idObj.id; } break; } }); return node; }); return tree; }; } module.exports = plugin;