| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | "use strict";const xnv = require("xml-name-validator");const { NAMESPACES } = require("./constants");function generatePrefix(map, newNamespace, prefixIndex) {  const generatedPrefix = "ns" + prefixIndex;  map[newNamespace] = [generatedPrefix];  return generatedPrefix;}function preferredPrefixString(map, ns, preferredPrefix) {  const candidateList = map[ns];  if (!candidateList) {    return null;  }  if (candidateList.includes(preferredPrefix)) {    return preferredPrefix;  }  return candidateList[candidateList.length - 1];}function serializeAttributeValue(value/* , requireWellFormed*/) {  if (value === null) {    return "";  }  // TODO: Check well-formedness  return value    .replace(/&/g, "&")    .replace(/"/g, """)    .replace(/</g, "<")    .replace(/>/g, ">")    .replace(/\t/g, "	")    .replace(/\n/g, "
")    .replace(/\r/g, "
");}function serializeAttributes(  element,  map,  localPrefixes,  ignoreNamespaceDefAttr,  requireWellFormed,  refs) {  let result = "";  const namespaceLocalnames = Object.create(null);  for (const attr of element.attributes) {    if (      requireWellFormed &&      namespaceLocalnames[attr.namespaceURI] &&      namespaceLocalnames[attr.namespaceURI].has(attr.localName)    ) {      throw new Error("Found duplicated attribute");    }    if (!namespaceLocalnames[attr.namespaceURI]) {      namespaceLocalnames[attr.namespaceURI] = new Set();    }    namespaceLocalnames[attr.namespaceURI].add(attr.localName);    const attributeNamespace = attr.namespaceURI;    let candidatePrefix = null;    if (attributeNamespace !== null) {      candidatePrefix = preferredPrefixString(        map,        attributeNamespace,        attr.prefix      );      if (attributeNamespace === NAMESPACES.XMLNS) {        if (          attr.value === NAMESPACES.XML ||          (attr.prefix === null && ignoreNamespaceDefAttr) ||          (attr.prefix !== null &&            localPrefixes[attr.localName] !== attr.value &&            map[attr.value].includes(attr.localName))        ) {          continue;        }        if (requireWellFormed && attr.value === NAMESPACES.XMLNS) {          throw new Error(            "The XMLNS namespace is reserved and cannot be applied as an element's namespace via XML parsing"          );        }        if (requireWellFormed && attr.value === "") {          throw new Error(            "Namespace prefix declarations cannot be used to undeclare a namespace"          );        }        if (attr.prefix === "xmlns") {          candidatePrefix = "xmlns";        }      } else if (candidatePrefix === null) {        candidatePrefix = generatePrefix(          map,          attributeNamespace,          refs.prefixIndex++        );        result += ` xmlns:${candidatePrefix}="${serializeAttributeValue(          attributeNamespace,          requireWellFormed        )}"`;      }    }    result += " ";    if (candidatePrefix !== null) {      result += candidatePrefix + ":";    }    if (      requireWellFormed &&      (attr.localName.includes(":") ||        !xnv.name(attr.localName) ||        (attr.localName === "xmlns" && attributeNamespace === null))    ) {      throw new Error("Invalid attribute localName value");    }    result += `${attr.localName}="${serializeAttributeValue(      attr.value,      requireWellFormed    )}"`;  }  return result;}module.exports.preferredPrefixString = preferredPrefixString;module.exports.generatePrefix = generatePrefix;module.exports.serializeAttributeValue = serializeAttributeValue;module.exports.serializeAttributes = serializeAttributes;
 |