Skip to content

Instantly share code, notes, and snippets.

@leggetter
Created February 3, 2025 09:10
Show Gist options
  • Save leggetter/27641b6fbb623a282463a48e067594b5 to your computer and use it in GitHub Desktop.
Save leggetter/27641b6fbb623a282463a48e067594b5 to your computer and use it in GitHub Desktop.
Convert an XML payload to JSON using a Hookdeck Transformation
// Bundle created using bundlejs:
var m=Object.create;var C=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var U=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports);var j=(t,r,e,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of I(r))!P.call(t,c)&&c!==e&&C(t,c,{get:()=>r[c],enumerable:!(s=w(r,c))||s.enumerable});return t};var $=(t,r,e)=>(e=t!=null?m(K(t)):{},j(r||!t||!t.__esModule?C(e,"default",{value:t,enumerable:!0}):e,t));var R=U((st,M)=>{"use strict";function F(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var N=t=>{if(!t)return null;let r={};switch(t.type){case"ELEMENT":{let e={},s=z(t.value.attributes),c=N(t.value.children);if(s&&(e=Object.assign(e,s)),c){let E=G(t.value.children);e=Object.assign(e,E)}r[t.value.type]=e;break}case"ATTRIBUTE":{let e=t.value;r[e.name]=e.value;break}case"CONTENT":return{content:t.value}}return r},G=t=>t&&Array.isArray(t)&&t.length!==0?X(t)?{content:t[0].value}:{children:t.map(N)}:null,X=t=>t&&Array.isArray(t)&&t.length===1&&t[0].type==="CONTENT",z=t=>t&&Array.isArray(t)?t.map(N).reduce((r,e)=>Object.assign(r,e),{}):null,V={convert:t=>N(t.value.children[0])},k={Token:(t,r)=>({type:t,value:r})},{Token:l}=k,A=l("EOF"),L=t=>t===" "||t===`
`||t==="\r"||t===" ",_=t=>t.replace(/'/g,"'"),W={createLexer:function(t){let r=null,e=(o=>{let u=0;for(;u<o.length&&L(o[u]);)u++;return((a,n)=>{if(a.startsWith("<?xml",n)){let h=a.length;for(;n<h;)if(a[n]!=="?")n++;else{if(a[n+1]===">")return n+2;n++}}return n})(o,u)})(t),s=[],c=()=>t[e],E=()=>r!==A&&e<t.length,f=o=>o==='"'||o==="'",T=()=>{for(;E()&&L(t[e]);)e++},O=o=>{if(E()){if(t[e]==="<"){let u="<";return e++,E()&&t[e]==="/"?(e++,u="</"):E()&&t[e]==="!"&&t[e+1]==="-"&&t[e+2]==="-"&&(e++,e++,e++,u="<!--"),u}if(c()==="/"){let u="/";return e++,E()&&c()===">"&&(e++,u="/>"),u}if(t[e]==="="||t[e]===">"){let u=t[e];return e++,u}}return y(!!o)},y=o=>{let u=o?/[^>=<]/u:/[a-zA-Z0-9_:-]/,a=e;for(;E()&&t[e].match(u);)e++;return _(t.substring(a,e))},v=()=>{let o=e;T();let u=e-o;if(E())if(r&&r.type==="OPEN_BRACKET"){T();let a=O(!1);r=l("ELEMENT_TYPE",a),s.push(a)}else if(r&&r.type==="ASSIGN"){E()&&f(c())&&e++;let a=t[e-1],n=e;for(;E()&&c()!==a;)e++;let h=_(t.substring(n,e));e++,r=l("ATTRIB_VALUE",h)}else{T();let a=O(!0);switch(a){case"=":r=r.type==="ATTRIB_NAME"?l("ASSIGN"):l("CONTENT",a);break;case"</":{let n=e;for(;t[e]!==">";)e++;r=l("CLOSE_ELEMENT",t.substring(n,e)),e++,s.pop();break}case"/>":{let n=s.pop();r=l("CLOSE_ELEMENT",n);break}case"<!--":{let n=["!","-","-"];for(;E()&&(n[2]!==">"||n[1]!=="-"||n[0]!=="-");)n.shift(),n.push(t[e]),e++;return v()}case">":r=l("CLOSE_BRACKET");break;case"<":r=l("OPEN_BRACKET");break;default:if(a&&a.length>0){if(r.type==="CLOSE_BRACKET"){let n="";c()!=="<"&&(n=y(!0)),r=l("CONTENT",a+n)}else if(r.type!=="ATTRIB_NAME"&&r.type!=="CONTENT")r.type==="CLOSE_ELEMENT"?(a=" ".repeat(u)+a,r=l("CONTENT",a)):r=l("ATTRIB_NAME",a);else{let n=" ".repeat(u)+a;r=l("CONTENT",n)}break}{let n='Unknown Syntax : "'+t[e]+'"';throw new Error(n)}}}else r=A;return r};return{peek:c,next:v,hasNext:E}}},{createLexer:Y}=W,{Token:Z}=k,[b,q,D,H]=["ROOT","ELEMENT","ATTRIBUTE","CONTENT"],i=(t,r)=>({type:t,value:r}),p=t=>i(H,t),g=(t,r,e)=>i(q,{type:t,attributes:r,children:e}),S=(t,r)=>i(D,{name:t,value:r}),d=(t,r)=>{let e=[];for(;t.hasNext();){let s=t.next();switch(s.type){case"OPEN_BRACKET":{let c=t.next(),[E,f]=J(t),T=[];f.type!=="CLOSE_ELEMENT"&&(T=d(t,c)),T&&T.length>0&&T[0].type==="CONTENT"&&(T=Q(T)),e.push(g(c.value,E,T));break}case"CLOSE_ELEMENT":if(s.value===r.value)return e;break;case"CONTENT":e.push(p(s.value));break;case"EOF":return e;default:throw new Error(`Unknown Lexem type: ${s.type} "${s.value}, scoping element: ${r.value}"`)}}return e},J=t=>{let r=[],e=t.peek();if(!t.hasNext()||e&&e.type==="CLOSE_BRACKET"||e&&e.type==="CLOSE_ELEMENT")return[r,e];for(e=t.next();t.hasNext()&&e&&e.type!=="CLOSE_BRACKET"&&e.type!=="CLOSE_ELEMENT";){let s=e;t.next();let c=t.next(),E=S(s.value,c.value);r.push(E),e=t.next()}return[r,e]};function Q(t){let r=[],e="";return t.forEach(s=>{s.type==="CONTENT"?e+=s.value:(e.length&&(r.push(p(e)),e=""),r.push(s))}),e.length&&r.push(p(e)),r}var tt={AttribNode:S,ContentNode:p,ElementNode:g,Node:i,transpile:function(t,r){let e=(s=>i(b,{children:d(s,Z(b,"ROOT"))}))(Y(t));return r?r.convert(e):e}},et=V,{transpile:x}=tt,rt=F({convertXML:function(t,r){return x(t,r||et)},createAST:function(t){return x(t)}});M.exports=rt});var B=$(R());var export_convertXML=B.convertXML;var export_createAST=B.createAST;
// comment out the `export as it doesn't exist in the Hookdeck runtime
// export{export_convertXML as convertXML,export_createAST as createAST};
addHandler('transform', (request, context) => {
// Transform the request object then return it.
const json = export_convertXML(request.body);
request.headers["content-type"] = "application/json"
request.body = json;
return request;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment