// Utility parsing and wrapping functions for calls to Gamma import convert from "xml-js"; // INPUT WRAPPERS const parseInputField = (fieldContents, fieldKey) => { if (fieldKey === "GammaInputType" || fieldKey === "GammaResponseType") return { _attributes: { "xsi:type": fieldContents } }; if (fieldContents.constructor === Object) return { [fieldKey]: sanitise(fieldContents) }; if (Array.isArray(fieldContents)) { const arrayOfParsedObjects = fieldContents.map((singleInputObject) => { return sanitise(singleInputObject); }); return { [fieldKey]: arrayOfParsedObjects }; } return { [fieldKey]: fieldContents }; }; const sanitise = (callObject) => { const sanitised = Object.keys(callObject).reduce((distilledObject, key) => { return { ...distilledObject, ...parseInputField(callObject[key], key) }; }, {}); return sanitised; }; export const getXml = (callObject, method) => { const sanitisedCallObject = sanitise(callObject); const fullCall = { _declaration: { _attributes: { version: "1.0", encoding: "utf-8" } }, XMLRequest: { _attributes: { "xmlns:xsd": "http://www.w3.org/2001/XMLSchema", "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", }, Description: { _text: method.name }, Item: { _attributes: { "xsi:type": method.type }, _text: "", ...sanitisedCallObject }, }, }; const xmlInner = convert.js2xml(fullCall, { compact: true, spaces: 2, fullTagEmptyElement: true }); const xmlWrapped = convert.js2xml({ _cdata: xmlInner }, { compact: true, spaces: 2, fullTagEmptyElement: true }); return xmlWrapped; }; // OUTPUT PARSERS const parseResponseField = (fieldContents, fieldKey, methodSpecs) => { if (fieldContents.constructor === Object && Object.keys(fieldContents).length === 0) return { [fieldKey]: "" }; if (fieldKey === "xs:schema") return {}; if (fieldKey === "mResults" && fieldContents.hasOwnProperty("diffgr:diffgram")) return { [fieldKey]: processAnyType(fieldContents["diffgr:diffgram"].NewDataSet.Table, methodSpecs, true), }; if ( methodSpecs.returnType === false && fieldKey === "_attributes" && fieldContents.hasOwnProperty("xmlns:xsi") && fieldContents.hasOwnProperty("xmlns:xsd") ) return { GammaResponseType: methodSpecs.responseWrapper }; if (fieldKey === "_attributes" && fieldContents.hasOwnProperty("xsi:type")) return { GammaResponseType: fieldContents["xsi:type"] }; if ( fieldKey === "_attributes" && fieldContents.hasOwnProperty("diffgr:id") && fieldContents.hasOwnProperty("msdata:rowOrder") ) return { GammaResponseType: "VisitorStatsDay" }; if (fieldContents.hasOwnProperty("_text")) return { [fieldKey]: fieldContents["_text"] }; if (fieldContents.hasOwnProperty("anyType")) return { [fieldKey]: processAnyType(fieldContents.anyType, methodSpecs) }; if (fieldContents.hasOwnProperty(fieldKey)) return { [fieldKey]: parseResponseField(fieldContents[fieldKey], fieldKey, methodSpecs) }; if (fieldContents.constructor === Object && Object.keys(fieldContents).length !== 0) { const formattedContents = Object.keys(fieldContents).reduce((distilledObject, key) => { return { ...distilledObject, ...parseResponseField(fieldContents[key], key, methodSpecs) }; }, {}); return { [fieldKey]: formattedContents }; } return { [fieldKey]: fieldContents }; }; const processAnyType = (anyType, methodSpecs, internal = false) => { // A single response needs converted for the array operations to work const anyTypeArray = Array.isArray(anyType) ? anyType : new Array(anyType); const reduced = anyTypeArray.map((verboseObject) => { const keys = Object.keys(verboseObject); const distilled = keys.reduce((distilledObject, key) => { return { ...distilledObject, ...parseResponseField(verboseObject[key], key, methodSpecs) }; }, {}); return distilled; }); const result = !internal && methodSpecs.returnType === false && reduced.length === 1 ? reduced[0] : reduced; // Only return an array if necessary return result; }; export const parseResponse = (rawResult, methodSpecs) => { const jsResponse = convert.xml2js(rawResult.ReceiveDataResult, { compact: true }); if (jsResponse.hasOwnProperty("LPUnsupported")) return { Message: `The Gamma server responded: ${jsResponse.LPUnsupported.MessageResponse._text}` }; const checkableExtraction = methodSpecs.returnType ? jsResponse[methodSpecs.responseWrapper][methodSpecs.returnType] : jsResponse[methodSpecs.responseWrapper]; if (Object.keys(checkableExtraction).length === 0 && checkableExtraction.constructor === Object) return {}; // Empty response from Gamma const anyType = methodSpecs.returnType ? checkableExtraction.anyType : checkableExtraction; return processAnyType(anyType, methodSpecs); };