in src/util/xml-helpers.js [268:339]
function mergeXml (src, dest, platform, clobber) {
// Do nothing for denied tags.
if (DENIED_TAGS.includes(String(src.tag))) return;
// Handle attributes
const omitAttrs = new Set(clobber ? [] : dest.keys());
const xferAttrs = src.keys().filter(k => !omitAttrs.has(k));
xferAttrs.forEach(attr => { dest.attrib[attr] = src.attrib[attr]; });
// Handle text
if (src.text && (clobber || !dest.text)) {
dest.text = src.text;
}
// Handle children
src.getchildren().forEach(mergeChild);
// Handle platform
if (platform) {
src.findall(`platform[@name="${platform}"]`).forEach(platformElement => {
platformElement.getchildren().forEach(mergeChild);
});
}
// Handle duplicate preference tags (by name attribute)
removeDuplicatePreferences(dest);
/** @param {et.Element} srcChild */
function mergeChild (srcChild) {
const srcTag = String(srcChild.tag);
const query = srcTag + '';
let destChild;
let shouldMerge = true;
if (DENIED_TAGS.includes(srcTag)) return;
if (SINGLETONS.includes(srcTag)) {
destChild = dest.find(query);
} else {
// Check for an exact match and if you find one don't add
destChild = dest.findall(query).find(el =>
textMatch(srcChild, el) && attribMatch(srcChild, el)
);
if (destChild) shouldMerge = false;
}
if (destChild) {
dest.remove(destChild);
} else {
destChild = et.Element(srcTag);
}
mergeXml(srcChild, destChild, platform, clobber && shouldMerge);
dest.append(destChild);
}
/** @param {et.Element} xml */
function removeDuplicatePreferences (xml) {
const prefs = xml.findall('preference[@name][@value]');
// reduce preference tags to a hashtable to remove dupes
const prefMap = new Map(
prefs.map(({ attrib: { name, value } }) => [name, value])
);
// remove all preferences
prefs.forEach(pref => xml.remove(pref));
// write new preferences
prefMap.forEach((value, name) => {
et.SubElement(xml, 'preference', { name, value });
});
}
}