text: import namespaces from 'svg-mixer/namespaces';
  import selectAttributes from './select-attributes';
  import arrayFrom from './array-from';
  
  const xLinkNS = namespaces.xlink.uri;
  const xLinkAttrName = 'xlink:href';
  
  // eslint-disable-next-line no-useless-escape
  const specialUrlCharsPattern = /[{}|\\\^\[\]`"<>]/g;
  
  function encoder(url) {
    return url.replace(specialUrlCharsPattern, (match) => {
      return `%${match[0].charCodeAt(0).toString(16).toUpperCase()}`;
    });
  }
  
  /**
   * @param {NodeList} nodes
   * @param {string} startsWith
   * @param {string} replaceWith
   * @return {NodeList}
   */
  function updateReferences(nodes, startsWith, replaceWith) {
    arrayFrom(nodes).forEach((node) => {
      const href = node.getAttribute(xLinkAttrName);
      if (href && href.indexOf(startsWith) === 0) {
        const newUrl = href.replace(startsWith, replaceWith);
        node.setAttributeNS(xLinkNS, xLinkAttrName, newUrl);
      }
    });
  
    return nodes;
  }
  
  /**
   * List of SVG attributes to update url() target in them
   */
  const attList = [
    'clipPath',
    'colorProfile',
    'src',
    'cursor',
    'fill',
    'filter',
    'marker',
    'markerStart',
    'markerMid',
    'markerEnd',
    'mask',
    'stroke',
    'style'
  ];
  
  const attSelector = attList.map(attr => `[${attr}]`).join(',');
  
  /**
   * Update URLs in svg image (like `fill="url(...)"`) and update referencing elements
   * @param {Element} svg
   * @param {NodeList} references
   * @param {string|RegExp} startsWith
   * @param {string} replaceWith
   * @return {void}
   *
   * @example
   * const sprite = document.querySelector('svg.sprite');
   * const usages = document.querySelectorAll('use');
   * updateUrls(sprite, usages, '#', 'prefix#');
   */
  export default function (svg, references, startsWith, replaceWith) {
    const startsWithEncoded = encoder(startsWith);
    const replaceWithEncoded = encoder(replaceWith);
  
    const nodes = svg.querySelectorAll(attSelector);
    const attrs = selectAttributes(nodes, ({ localName, value }) => {
      return attList.indexOf(localName) !== -1 && value.indexOf(`url(${startsWithEncoded}`) !== -1;
    });
  
    attrs.forEach(attr => attr.value = attr.value.replace(startsWithEncoded, replaceWithEncoded));
    updateReferences(references, startsWithEncoded, replaceWithEncoded);
  }
  