120 lines
2.8 KiB
JavaScript
120 lines
2.8 KiB
JavaScript
/* 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;
|