diff options
Diffstat (limited to 'comm/mailnews/base/src/JXON.jsm')
-rw-r--r-- | comm/mailnews/base/src/JXON.jsm | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/JXON.jsm b/comm/mailnews/base/src/JXON.jsm new file mode 100644 index 0000000000..00c1f2bb1f --- /dev/null +++ b/comm/mailnews/base/src/JXON.jsm @@ -0,0 +1,159 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// This is a modification of the JXON parsers found on the page +// <https://developer.mozilla.org/en-US/docs/JXON> + +var EXPORTED_SYMBOLS = ["JXON"]; + +var JXON = new (function () { + const sValueProp = "value"; /* you can customize these values */ + const sAttributesProp = "attr"; + const sAttrPref = "@"; + const sElementListPrefix = "$"; + const sConflictSuffix = "_"; // used when there's a name conflict with special JXON properties + const aCache = []; + const rIsBool = /^(?:true|false)$/i; + + function parseText(sValue) { + if (rIsBool.test(sValue)) { + return sValue.toLowerCase() === "true"; + } + if (isFinite(sValue)) { + return parseFloat(sValue); + } + if (isFinite(Date.parse(sValue))) { + return new Date(sValue); + } + return sValue; + } + + function EmptyTree() {} + EmptyTree.prototype = { + toString() { + return "null"; + }, + valueOf() { + return null; + }, + }; + + function objectify(vValue) { + if (vValue === null) { + return new EmptyTree(); + } else if (vValue instanceof Object) { + return vValue; + } + return new vValue.constructor(vValue); // What does this? copy? + } + + function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) { + const nLevelStart = aCache.length; + const bChildren = oParentNode.hasChildNodes(); + const bAttributes = oParentNode.attributes && oParentNode.attributes.length; + const bHighVerb = Boolean(nVerb & 2); + + var sProp = 0; + var vContent = 0; + var nLength = 0; + var sCollectedTxt = ""; + var vResult = bHighVerb + ? {} + : /* put here the default value for empty nodes: */ true; + + if (bChildren) { + for ( + var oNode, nItem = 0; + nItem < oParentNode.childNodes.length; + nItem++ + ) { + oNode = oParentNode.childNodes.item(nItem); + if (oNode.nodeType === 4) { + // CDATASection + sCollectedTxt += oNode.nodeValue; + } else if (oNode.nodeType === 3) { + // Text + sCollectedTxt += oNode.nodeValue; + } else if (oNode.nodeType === 1) { + // Element + aCache.push(oNode); + } + } + } + + const nLevelEnd = aCache.length; + const vBuiltVal = parseText(sCollectedTxt); + + if (!bHighVerb && (bChildren || bAttributes)) { + vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; + } + + for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) { + sProp = aCache[nElId].nodeName; + if (sProp == sValueProp || sProp == sAttributesProp) { + sProp = sProp + sConflictSuffix; + } + vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr); + if (!vResult.hasOwnProperty(sProp)) { + vResult[sProp] = vContent; + vResult[sElementListPrefix + sProp] = []; + } + vResult[sElementListPrefix + sProp].push(vContent); + nLength++; + } + + if (bAttributes) { + const nAttrLen = oParentNode.attributes.length; + const sAPrefix = bNesteAttr ? "" : sAttrPref; + const oAttrParent = bNesteAttr ? {} : vResult; + + for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) { + oAttrib = oParentNode.attributes.item(nAttrib); + oAttrParent[sAPrefix + oAttrib.name] = parseText(oAttrib.value); + } + + if (bNesteAttr) { + if (bFreeze) { + Object.freeze(oAttrParent); + } + vResult[sAttributesProp] = oAttrParent; + nLength -= nAttrLen - 1; + } + } + + if ( + nVerb === 3 || + ((nVerb === 2 || (nVerb === 1 && nLength > 0)) && sCollectedTxt) + ) { + vResult[sValueProp] = vBuiltVal; + } else if (!bHighVerb && nLength === 0 && sCollectedTxt) { + vResult = vBuiltVal; + } + + if (bFreeze && (bHighVerb || nLength > 0)) { + Object.freeze(vResult); + } + + aCache.length = nLevelStart; + + return vResult; + } + + this.build = function ( + oXMLParent, + nVerbosity /* optional */, + bFreeze /* optional */, + bNesteAttributes /* optional */ + ) { + const _nVerb = + typeof nVerbosity === "number" + ? nVerbosity & 3 + : /* put here the default verbosity level: */ 1; + return createObjTree( + oXMLParent, + _nVerb, + bFreeze || false, + bNesteAttributes !== undefined ? bNesteAttributes : _nVerb === 3 + ); + }; +})(); |