@lit-pigeon/parser-mjml 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const C=require("htmlparser2"),g=require("@lit-pigeon/core");function I(t,n){const e={};for(const r of t)switch(r.tag){case"mj-preview":e.previewText=r.text;break;case"mj-attributes":for(const a of r.children)a.tag==="mj-all"&&a.attrs["font-family"]&&(e.fontFamily=a.attrs["font-family"]);break}return e}function u(t,n=0){if(!t)return{top:n,right:n,bottom:n,left:n};const e=t.trim().split(/\s+/).map(S);switch(e.length){case 1:return{top:e[0],right:e[0],bottom:e[0],left:e[0]};case 2:return{top:e[0],right:e[1],bottom:e[0],left:e[1]};case 3:return{top:e[0],right:e[1],bottom:e[2],left:e[1]};case 4:return{top:e[0],right:e[1],bottom:e[2],left:e[3]};default:return{top:n,right:n,bottom:n,left:n}}}function S(t){const n=parseFloat(t);return isNaN(n)?0:n}function o(t,n,e=""){return t[n]??e}function p(t,n,e=0){const r=t[n];if(r===void 0||r==="")return e;const a=parseFloat(r);return isNaN(a)?e:a}function A(t,n){return{id:g.generateId(),type:"text",values:{content:n,padding:u(o(t,"padding"),10),lineHeight:o(t,"line-height","1.5"),textAlign:o(t,"align","left")}}}function T(t){const n=o(t,"width"),e=n&&parseInt(n,10)||"auto";return{id:g.generateId(),type:"image",values:{src:o(t,"src"),alt:o(t,"alt"),width:e,href:o(t,"href")||void 0,padding:u(o(t,"padding"),10),alignment:o(t,"align","center"),borderRadius:p(t,"border-radius",0)}}}function B(t,n){const e=n.trim(),r=/^<p[\s>]/i.test(e)?e:`<p>${e}</p>`;return{id:g.generateId(),type:"button",values:{content:r,href:o(t,"href","#"),backgroundColor:o(t,"background-color","#3b82f6"),textColor:o(t,"color","#ffffff"),borderRadius:p(t,"border-radius",4),padding:u(o(t,"padding"),10),innerPadding:u(o(t,"inner-padding"),12),fontSize:p(t,"font-size",16),fontWeight:o(t,"font-weight","600"),alignment:o(t,"align","center"),fullWidth:o(t,"width")==="100%"}}}function N(t){return{id:g.generateId(),type:"divider",values:{borderColor:o(t,"border-color","#e2e8f0"),borderWidth:p(t,"border-width",1),borderStyle:o(t,"border-style","solid"),padding:u(o(t,"padding"),10),width:o(t,"width","100%")}}}function D(t){return{id:g.generateId(),type:"spacer",values:{height:p(t,"height",20)}}}const W=["facebook","twitter","instagram","linkedin","youtube","tiktok"];function $(t){const n=t.toLowerCase();for(const e of W)if(n.includes(e))return e;return"custom"}function F(t,n){const e=n.map(r=>{const c={type:$(o(r.attrs,"name","custom")),href:o(r.attrs,"href","#"),label:r.innerText.trim()||void 0},s=o(r.attrs,"src");return s&&(c.iconUrl=s),c});return{id:g.generateId(),type:"social",values:{icons:e,iconSize:p(t,"icon-size",32),spacing:p(t,"icon-padding",8),alignment:o(t,"align","center"),padding:u(o(t,"padding"),10)}}}function P(t){const n=t.match(/^<div\s+style="padding:\s*([^"]*)">([\s\S]*)<\/div>$/);return n?{id:g.generateId(),type:"html",values:{content:n[2],padding:u(n[1],0)}}:{id:g.generateId(),type:"html",values:{content:t,padding:u(void 0,0)}}}function z(t,n){const e=n.map(r=>{const a={href:o(r.attrs,"href","#"),text:r.innerText.trim()||"Link"},c=o(r.attrs,"color");c&&(a.color=c);const s=o(r.attrs,"font-weight");s&&(a.fontWeight=s);const i=o(r.attrs,"text-decoration");i&&(a.textDecoration=i);const d=o(r.attrs,"padding");return d&&(a.padding=d),a});return{id:g.generateId(),type:"navbar",values:{links:e,hamburger:o(t,"hamburger","hamburger"),alignment:o(t,"align","center"),padding:u(o(t,"padding"),10),linkColor:o(t,"ico-color","#000000"),linkFontSize:p(t,"font-size",14),linkPadding:o(t,"link-padding","10px 15px")}}}function w(t,n){const e=t.attrs,r=[];for(const a of t.children){const c=H(a,n);c&&r.push(c)}return{id:g.generateId(),type:"column",attributes:{backgroundColor:o(e,"background-color")||void 0,padding:u(o(e,"padding"),0),borderRadius:p(e,"border-radius",0)||void 0,verticalAlign:o(e,"vertical-align","top")},blocks:r}}function H(t,n){switch(t.tag){case"mj-text":return A(t.attrs,t.text);case"mj-image":return T(t.attrs);case"mj-button":return B(t.attrs,t.text);case"mj-divider":return N(t.attrs);case"mj-spacer":return D(t.attrs);case"mj-social":{const e=t.children.filter(r=>r.tag==="mj-social-element").map(r=>({attrs:r.attrs,innerText:r.text}));return F(t.attrs,e)}case"mj-raw":return P(t.text);case"mj-navbar":{const e=t.children.filter(r=>r.tag==="mj-navbar-link").map(r=>({attrs:r.attrs,innerText:r.text}));return z(t.attrs,e)}default:return n.push({message:`Unknown block element: ${t.tag}`,tag:t.tag}),null}}function v(t,n){const e=t.attrs,r=[];for(const i of t.children)if(i.tag==="mj-column")r.push(w(i,n));else if(i.tag==="mj-group")for(const d of i.children)d.tag==="mj-column"&&r.push(w(d,n));else n.push({message:`Unexpected section child: ${i.tag}`,tag:i.tag});r.length===0&&r.push({id:g.generateId(),type:"column",attributes:{padding:u(void 0,0),verticalAlign:"top"},blocks:[]});const a=R(r),s=o(e,"full-width")==="full-width";return{id:g.generateId(),type:"row",attributes:{backgroundColor:o(e,"background-color")||void 0,backgroundImage:o(e,"background-url")||void 0,padding:u(o(e,"padding"),0),fullWidth:s},columns:r,columnRatios:a,locked:!1}}function R(t,n){const e=t.length,r=Math.floor(12/e);return t.map(()=>r)}function O(t,n){return{id:g.generateId(),type:"hero",values:{backgroundUrl:o(t,"background-url"),backgroundPosition:o(t,"background-position","center center"),mode:o(t,"mode","fluid-height"),width:p(t,"width",600),height:p(t,"height",400),verticalAlign:o(t,"vertical-align","middle"),padding:u(o(t,"padding"),0),innerPadding:u(void 0,20),backgroundColor:o(t,"background-color","#ffffff"),content:n}}}function U(t,n){const e=p(t.attrs,"width",600),r=o(t.attrs,"background-color","#f4f4f5"),a=[];let c;const s=i=>(c&&(i.attributes.condition=c,c=void 0),i);for(const i of t.children)switch(i.tag){case"mj-raw":{const d=/\{\{#if\s+([^}]+?)\s*\}\}/.exec(i.text??"");d&&(c=d[1].trim());break}case"mj-section":a.push(s(v(i,n)));break;case"mj-hero":{const d=_(i),l=O(i.attrs,d),m={id:g.generateId(),type:"column",attributes:{padding:u(void 0,0),verticalAlign:"top"},blocks:[l]},f={id:g.generateId(),type:"row",attributes:{padding:u(void 0,0),fullWidth:!1},columns:[m],columnRatios:[12],locked:!1};a.push(s(f));break}case"mj-wrapper":for(const d of i.children)d.tag==="mj-section"&&a.push(s(v(d,n)));break;default:n.push({message:`Unknown body child element: ${i.tag}`,tag:i.tag});break}return{width:e,backgroundColor:r,rows:a}}function _(t){const n=[];for(const e of t.children)(e.tag==="mj-text"||e.tag==="mj-button")&&n.push(e.text);return n.join("")||"<p>Hero Content</p>"}function M(t){const n={tag:"root",attrs:{},children:[],text:""},e=[n],r=new Set(["mj-text","mj-button","mj-raw","mj-preview","mj-social-element","mj-navbar-link"]),a=new Set(["mj-image","mj-divider","mj-spacer","mj-all","mj-class","mj-font","mj-breakpoint"]);let c=null,s="",i=0;const d=new C.Parser({onopentag(l,m){if(c){const k=Object.entries(m).map(([x,y])=>`${x}="${y}"`).join(" ");s+=k?`<${l} ${k}>`:`<${l}>`,i++;return}const f={tag:l,attrs:m,children:[],text:""};e[e.length-1].children.push(f),!a.has(l)&&(e.push(f),r.has(l)&&(c={node:f,depth:0},s="",i=0))},ontext(l){if(c){s+=l;return}const m=e[e.length-1];m.text+=l},onclosetag(l){if(c){if(i>0){s+=`</${l}>`,i--;return}c.node.text=s,c=null,s="",i=0,e.length>1&&e[e.length-1].tag===l&&e.pop();return}a.has(l)||e.length>1&&e[e.length-1].tag===l&&e.pop()}},{recognizeSelfClosing:!0,lowerCaseTags:!0,lowerCaseAttributeNames:!0});return d.write(t),d.end(),n}function b(t,n){if(t.tag===n)return t;for(const e of t.children){const r=b(e,n);if(r)return r}}function E(t,n){const e=[],r=M(t),a=b(r,"mjml");if(!a)return e.push({message:"No <mjml> root element found"}),{document:j(),warnings:e};const c=b(a,"mj-head"),s=b(a,"mj-body");let i={};if(c&&(i=I(c.children.map(f=>({tag:f.tag,attrs:f.attrs,children:f.children.map(h=>({tag:h.tag,attrs:h.attrs,children:[],text:h.text})),text:f.text})))),!s)return e.push({message:"No <mj-body> element found"}),{document:j(),warnings:e};const d=U(s,e),l=new Date().toISOString();return{document:{version:"1.0",metadata:{name:"Imported Template",previewText:i.previewText,createdAt:l,updatedAt:l},body:{attributes:{width:d.width,backgroundColor:d.backgroundColor,fontFamily:i.fontFamily??"Arial, Helvetica, sans-serif",contentAlignment:"center"},rows:d.rows}},warnings:e}}function j(){const t=new Date().toISOString();return{version:"1.0",metadata:{name:"Imported Template",createdAt:t,updatedAt:t},body:{attributes:{width:600,backgroundColor:"#f4f4f5",fontFamily:"Arial, Helvetica, sans-serif",contentAlignment:"center"},rows:[]}}}exports.mjmlToDocument=E;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("htmlparser2"),m=require("@lit-pigeon/core");function F(t,n){const e={attributeDefaults:{all:{},tags:{},classes:{}}},r=[];for(const o of t)switch(o.tag){case"mj-preview":e.previewText=o.text;break;case"mj-attributes":for(const a of o.children){const l=e.attributeDefaults;if(a.tag==="mj-all")Object.assign(l.all,a.attrs);else if(a.tag==="mj-class"){const{name:s,...c}=a.attrs;s&&(l.classes[s]={...l.classes[s],...c})}else l.tags[a.tag]={...l.tags[a.tag],...a.attrs}}e.attributeDefaults.all["font-family"]&&(e.fontFamily=e.attributeDefaults.all["font-family"]);break;case"mj-style":o.attrs.inline!=="inline"&&o.text.trim()&&r.push(o.text.trim());break}return r.length>0&&(e.css=r.join(`
2
+ `)),e}function f(t,n=0){if(!t)return{top:n,right:n,bottom:n,left:n};const e=t.trim().split(/\s+/).map(H);switch(e.length){case 1:return{top:e[0],right:e[0],bottom:e[0],left:e[0]};case 2:return{top:e[0],right:e[1],bottom:e[0],left:e[1]};case 3:return{top:e[0],right:e[1],bottom:e[2],left:e[1]};case 4:return{top:e[0],right:e[1],bottom:e[2],left:e[3]};default:return{top:n,right:n,bottom:n,left:n}}}function H(t){const n=parseFloat(t);return isNaN(n)?0:n}function i(t,n,e=""){return t[n]??e}function b(t,n,e=0){const r=t[n];if(r===void 0||r==="")return e;const o=parseFloat(r);return isNaN(o)?e:o}function L(t,n){return{id:m.generateId(),type:"text",values:{content:n,padding:f(i(t,"padding"),10),lineHeight:i(t,"line-height","1.5"),textAlign:i(t,"align","left"),cssClass:i(t,"css-class")||void 0}}}function U(t){const n=i(t,"width"),e=n&&parseInt(n,10)||"auto";return{id:m.generateId(),type:"image",values:{src:i(t,"src"),alt:i(t,"alt"),width:e,href:i(t,"href")||void 0,padding:f(i(t,"padding"),10),alignment:i(t,"align","center"),borderRadius:b(t,"border-radius",0),cssClass:i(t,"css-class")||void 0}}}function W(t,n){const e=n.trim(),r=/^<p[\s>]/i.test(e)?e:`<p>${e}</p>`;return{id:m.generateId(),type:"button",values:{content:r,href:i(t,"href","#"),backgroundColor:i(t,"background-color","#3b82f6"),textColor:i(t,"color","#ffffff"),borderRadius:b(t,"border-radius",4),padding:f(i(t,"padding"),10),innerPadding:f(i(t,"inner-padding"),12),fontSize:b(t,"font-size",16),fontWeight:i(t,"font-weight","600"),alignment:i(t,"align","center"),fullWidth:i(t,"width")==="100%",cssClass:i(t,"css-class")||void 0}}}function P(t){return{id:m.generateId(),type:"divider",values:{borderColor:i(t,"border-color","#e2e8f0"),borderWidth:b(t,"border-width",1),borderStyle:i(t,"border-style","solid"),padding:f(i(t,"padding"),10),width:i(t,"width","100%")}}}function q(t){return{id:m.generateId(),type:"spacer",values:{height:b(t,"height",20)}}}const G=["facebook","twitter","instagram","linkedin","youtube","tiktok"];function M(t){const n=t.toLowerCase();for(const e of G)if(n.includes(e))return e;return"custom"}function X(t,n){const e=n.map(r=>{const a={type:M(i(r.attrs,"name","custom")),href:i(r.attrs,"href","#"),label:r.innerText.trim()||void 0},l=i(r.attrs,"src");return l&&(a.iconUrl=l),a});return{id:m.generateId(),type:"social",values:{icons:e,iconSize:b(t,"icon-size",32),spacing:b(t,"icon-padding",8),alignment:i(t,"align","center"),padding:f(i(t,"padding"),10)}}}function K(t){const n=t.match(/^<div\s+style="padding:\s*([^"]*)">([\s\S]*)<\/div>$/);return n?{id:m.generateId(),type:"html",values:{content:n[2],padding:f(n[1],0)}}:{id:m.generateId(),type:"html",values:{content:t,padding:f(void 0,0)}}}const V={align:"left",border:"none",cellpadding:"0",cellspacing:"0",color:"#000000","font-family":"Ubuntu, Helvetica, Arial, sans-serif","font-size":"13px","line-height":"22px",padding:"10px 25px","table-layout":"auto",width:"100%"};function Y(t,n){const e={...V,...t},r=e.width.endsWith("%")||e.width==="auto"?e.width:String(parseInt(e.width,10)),o=parseFloat(e.cellspacing.replace(/[^\d.]/g,"")),a=[`color:${e.color}`,`font-family:${e["font-family"]}`,`font-size:${e["font-size"]}`,`line-height:${e["line-height"]}`,`table-layout:${e["table-layout"]}`,`width:${e.width}`,`border:${e.border}`,...o>0?["border-collapse:separate"]:[]].map(s=>`${s};`).join(""),l=[];return e.align!=="left"&&l.push(`align="${j(e.align)}"`),l.push(`cellpadding="${j(e.cellpadding)}"`,`cellspacing="${j(e.cellspacing)}"`),t.role&&l.push(`role="${j(t.role)}"`),l.push(`width="${j(r)}"`,'border="0"',`style="${j(a)}"`),{id:m.generateId(),type:"html",values:{content:`<table ${l.join(" ")}>${n.trim()}</table>`,padding:f(i(e,"padding"),0)}}}function j(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Z(t,n){const e=i(t,"base-url"),r=n.map(o=>{const a={href:e+i(o.attrs,"href","#"),text:o.innerText.trim()||"Link"},l=i(o.attrs,"color");l&&(a.color=l);const s=i(o.attrs,"font-weight");s&&(a.fontWeight=s);const c=i(o.attrs,"text-decoration");c&&(a.textDecoration=c);const g=i(o.attrs,"padding");return g&&(a.padding=g),a});return{id:m.generateId(),type:"navbar",values:{links:r,hamburger:i(t,"hamburger","hamburger"),alignment:i(t,"align","center"),padding:f(i(t,"padding"),10),linkColor:i(t,"ico-color","#000000"),linkFontSize:b(t,"font-size",14),linkPadding:i(t,"link-padding","10px 15px")}}}function C(t,n){const e=t.attrs,r=[];for(const o of t.children){const a=J(o,n);a&&r.push(a)}return{id:m.generateId(),type:"column",attributes:{backgroundColor:i(e,"background-color")||void 0,padding:f(i(e,"padding"),0),borderRadius:b(e,"border-radius",0)||void 0,verticalAlign:i(e,"vertical-align","top"),cssClass:i(e,"css-class")||void 0},blocks:r}}function J(t,n){switch(t.tag){case"mj-text":return L(t.attrs,t.text);case"mj-image":return U(t.attrs);case"mj-button":return W(t.attrs,t.text);case"mj-divider":return P(t.attrs);case"mj-spacer":return q(t.attrs);case"mj-social":{const e=t.children.filter(r=>r.tag==="mj-social-element").map(r=>({attrs:r.attrs,innerText:r.text}));return X(t.attrs,e)}case"mj-raw":return K(t.text);case"mj-table":return Y(t.attrs,t.text);case"mj-navbar":{const e=t.children.filter(r=>r.tag==="mj-navbar-link").map(r=>({attrs:r.attrs,innerText:r.text}));return Z(t.attrs,e)}default:return n.push({message:`Unknown block element: ${t.tag}`,tag:t.tag}),null}}function I(t,n){const e=t.attrs,r=[];for(const s of t.children)if(s.tag==="mj-column")r.push(C(s,n));else if(s.tag==="mj-group")for(const c of s.children)c.tag==="mj-column"&&r.push(C(c,n));else n.push({message:`Unexpected section child: ${s.tag}`,tag:s.tag});r.length===0&&r.push({id:m.generateId(),type:"column",attributes:{padding:f(void 0,0),verticalAlign:"top"},blocks:[]});const o=Q(r),l=i(e,"full-width")==="full-width";return{id:m.generateId(),type:"row",attributes:{backgroundColor:i(e,"background-color")||void 0,backgroundImage:i(e,"background-url")||void 0,padding:f(i(e,"padding"),0),fullWidth:l,cssClass:i(e,"css-class")||void 0},columns:r,columnRatios:o,locked:!1}}function Q(t,n){const e=t.length,r=Math.floor(12/e);return t.map(()=>r)}function tt(t,n,e){return{id:m.generateId(),type:"hero",values:{backgroundUrl:i(t,"background-url"),backgroundPosition:i(t,"background-position","center center"),mode:i(t,"mode","fluid-height"),width:b(t,"width",600),height:b(t,"height",400),verticalAlign:i(t,"vertical-align","middle"),padding:f(i(t,"padding"),0),innerPadding:f(e,20),backgroundColor:i(t,"background-color","#ffffff"),content:n}}}const et=[["font-style","font-style"],["font-weight","font-weight"],["letter-spacing","letter-spacing"],["line-height","line-height"],["text-align","align"],["text-decoration","text-decoration"],["text-transform","text-transform"],["height","height"]],nt="1.5";function A(t,n,e){const r=et.filter(([o,a])=>t[a]&&!(o==="line-height"&&t[a]===nt)).concat(!e&&t.padding?[["padding","padding"]]:[]).map(([o,a])=>`${o}:${t[a]};`).join("");return r?`<div style="${w(r)}">${n}</div>`:e?n:`<div>${n}</div>`}const rt={align:"center","background-color":"#414141",border:"none","border-radius":"3px",color:"#ffffff","font-family":"Ubuntu, Helvetica, Arial, sans-serif","font-size":"13px","font-weight":"normal","inner-padding":"10px 25px","line-height":"120%",padding:"10px 25px",target:"_blank","text-decoration":"none","text-transform":"none","vertical-align":"middle"};function ot(t,n){const e={...rt,...t},r=e["background-color"],o=`border:${e.border};border-radius:${e["border-radius"]};cursor:auto;mso-padding-alt:${e["inner-padding"]};background:${r};`,a=`display:inline-block;background:${r};color:${e.color};font-family:${e["font-family"]};font-size:${e["font-size"]};font-weight:${e["font-weight"]};line-height:${e["line-height"]};margin:0;text-decoration:${e["text-decoration"]};text-transform:${e["text-transform"]};padding:${e["inner-padding"]};mso-padding-alt:0px;border-radius:${e["border-radius"]};`,l=e.href?`<a href="${w(e.href)}" target="${w(e.target)}" style="${w(a)}">${n.trim()}</a>`:`<p style="${w(a)}">${n.trim()}</p>`;return`<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"><tr><td align="${w(e.align)}" style="padding:${w(e.padding)};"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;"><tr><td align="center"${r==="none"?"":` bgcolor="${w(r)}"`} role="presentation" valign="${w(e["vertical-align"])}" style="${w(o)}">${l}</td></tr></table></td></tr></table>`}function w(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function it(t,n){const e=b(t.attrs,"width",600),r=i(t.attrs,"background-color","#f4f4f5"),o=[];let a;const l=s=>(a&&(s.attributes.condition=a,a=void 0),s);for(const s of t.children)switch(s.tag){case"mj-raw":{const c=/\{\{#if\s+([^}]+?)\s*\}\}/.exec(s.text??"");c&&(a=c[1].trim());break}case"mj-section":o.push(l(I(s,n)));break;case"mj-hero":{const c=at(s,n),g=tt(s.attrs,c.content,c.innerPadding),p={id:m.generateId(),type:"column",attributes:{padding:f(void 0,0),verticalAlign:"top"},blocks:[g]},d={id:m.generateId(),type:"row",attributes:{padding:f(void 0,0),fullWidth:!1},columns:[p],columnRatios:[12],locked:!1};o.push(l(d));break}case"mj-wrapper":n.push({message:"mj-wrapper styling (padding, background-color) was dropped: the document model has no wrapper; its sections were imported unwrapped",tag:"mj-wrapper"});for(const c of s.children)c.tag==="mj-section"&&o.push(l(I(c,n)));break;default:n.push({message:`Unknown body child element: ${s.tag}`,tag:s.tag});break}return{width:e,backgroundColor:r,rows:o}}function at(t,n){const[e]=t.children;if(t.children.length===1&&e.tag==="mj-text")return{content:A(e.attrs,e.text,!0),innerPadding:e.attrs.padding};const r=[];for(const o of t.children)o.tag==="mj-text"?r.push(A(o.attrs,o.text,!1)):o.tag==="mj-button"?r.push(ot(o.attrs,o.text)):n.push({message:`Unsupported mj-hero child element: ${o.tag}`,tag:o.tag});return{content:r.join("")||"<p>Hero Content</p>"}}const st=new Set(["mj-section","mj-column","mj-text","mj-button","mj-image"]);function R(t,n,e){const{"mj-class":r="",...o}=t.attrs,a=r.split(/\s+/).filter(Boolean).reduce((s,c)=>{const g=n.classes[c]??{},p=s["css-class"]&&g["css-class"]?{"css-class":`${s["css-class"]} ${g["css-class"]}`}:{};return{...s,...g,...p}},{});t.attrs={...n.all,...n.tags[t.tag],...a,...o};const l=t.attrs["css-class"];l&&!st.has(t.tag)&&e.push({message:`css-class "${l}" on <${t.tag}> was dropped`,tag:t.tag});for(const s of t.children)R(s,n,e)}const E=new Set(["address","article","aside","blockquote","center","dd","div","dl","dt","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hr","li","main","nav","ol","p","pre","section","table","tbody","td","tfoot","th","thead","tr","ul"]),D=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),lt="14px",ct="#000000";function z(t,n){if(t.tag==="mj-text"){const{color:e,"font-size":r,"font-family":o}=t.attrs,a=[];e&&e.toLowerCase()!==ct&&a.push(`color: ${e}`),r&&r!==lt&&a.push(`font-size: ${r}`),o&&o!==n&&a.push(`font-family: ${o}`),a.length>0&&(t.text=dt(t.text,`<span style="${ut(a.join("; "))}">`));return}for(const e of t.children)z(e,n)}function dt(t,n){const e=[];let r=-1,o=-1,a=!1,l=0;const s=()=>{r>=0&&a&&e.push([r,n],[o,"</span>"]),r=-1,a=!1},c=(d,h)=>{r<0&&(r=d),o=h},g=new _.Parser({onopentag(d){if(l===0&&E.has(d)){s();return}c(g.startIndex,g.endIndex+1),D.has(d)?a=!0:l++},onclosetag(d,h){if(!D.has(d)){if(l===0){E.has(d)&&s();return}l--,h||(o=g.endIndex+1)}},ontext(d){r<0&&!d.trim()||(c(g.startIndex,g.endIndex+1),d.trim()&&(a=!0))},oncomment(){r>=0&&(o=g.endIndex+1)}},{recognizeSelfClosing:!0,lowerCaseTags:!0});g.write(t),g.end(),s();let p=t;for(const[d,h]of e.reverse())p=p.slice(0,d)+h+p.slice(d);return p}function ut(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function gt(t){const n={tag:"root",attrs:{},children:[],text:""},e=[n],r=new Set(["mj-text","mj-button","mj-raw","mj-preview","mj-social-element","mj-navbar-link","mj-table"]),o=new Set(["mj-image","mj-divider","mj-spacer","mj-all","mj-class","mj-font","mj-breakpoint"]),a=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),l=new Set(["mj-text","mj-button","mj-raw"]),s=new Set(["style","script"]),c=u=>u.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),g=u=>u.replace(/&/g,"&amp;").replace(/"/g,"&quot;");let p=null,d="",h=0,x=!1;const y=new _.Parser({onopentag(u,v){if(p){const N=l.has(p.node.tag),S=Object.entries(v).map(([O,T])=>`${O}="${N?g(T):T}"`).join(" ");d+=S?`<${u} ${S}>`:`<${u}>`,a.has(u)||h++,s.has(u)&&(x=!0);return}const k={tag:u,attrs:v,children:[],text:""};e[e.length-1].children.push(k),!o.has(u)&&(e.push(k),r.has(u)&&(p={node:k,depth:0},d="",h=0))},ontext(u){if(p){const k=l.has(p.node.tag)&&!x;d+=k?c(u):u;return}const v=e[e.length-1];v.text+=u},onclosetag(u){if(p){if(a.has(u))return;if(h>0){d+=`</${u}>`,h--,s.has(u)&&(x=!1);return}p.node.text=d,p=null,d="",h=0,e.length>1&&e[e.length-1].tag===u&&e.pop();return}o.has(u)||e.length>1&&e[e.length-1].tag===u&&e.pop()},oncomment(u){p&&(d+=`<!--${u}-->`)}},{recognizeSelfClosing:!0,lowerCaseTags:!0,lowerCaseAttributeNames:!0});return y.write(t),y.end(),n}function $(t,n){if(t.tag===n)return t;for(const e of t.children){const r=$(e,n);if(r)return r}}function pt(t,n){const e=[],r=gt(t),o=$(r,"mjml");if(!o)return e.push({message:"No <mjml> root element found"}),{document:B(),warnings:e};const a=$(o,"mj-head"),l=$(o,"mj-body");let s={attributeDefaults:{all:{},tags:{},classes:{}}};if(a&&(s=F(a.children.map(h=>({tag:h.tag,attrs:h.attrs,children:h.children.map(x=>({tag:x.tag,attrs:x.attrs,children:[],text:x.text})),text:h.text})))),!l)return e.push({message:"No <mj-body> element found"}),{document:B(),warnings:e};const c=s.fontFamily??"Arial, Helvetica, sans-serif";R(l,s.attributeDefaults,e),z(l,c);const g=it(l,e),p=new Date().toISOString();return{document:{version:"1.0",metadata:{name:"Imported Template",previewText:s.previewText,createdAt:p,updatedAt:p},body:{attributes:{width:g.width,backgroundColor:g.backgroundColor,fontFamily:c,contentAlignment:"center",css:s.css},rows:g.rows}},warnings:e}}function B(){const t=new Date().toISOString();return{version:"1.0",metadata:{name:"Imported Template",createdAt:t,updatedAt:t},body:{attributes:{width:600,backgroundColor:"#f4f4f5",fontFamily:"Arial, Helvetica, sans-serif",contentAlignment:"center"},rows:[]}}}exports.mjmlToDocument=pt;
package/dist/index.js CHANGED
@@ -1,23 +1,36 @@
1
- import { Parser as C } from "htmlparser2";
2
- import { generateId as p } from "@lit-pigeon/core";
3
- function S(t, n) {
4
- const e = {};
1
+ import { Parser as _ } from "htmlparser2";
2
+ import { generateId as m } from "@lit-pigeon/core";
3
+ function H(t, n) {
4
+ const e = { attributeDefaults: { all: {}, tags: {}, classes: {} } }, r = [];
5
5
  for (const o of t)
6
6
  switch (o.tag) {
7
7
  case "mj-preview":
8
8
  e.previewText = o.text;
9
9
  break;
10
10
  case "mj-attributes":
11
- for (const a of o.children)
12
- a.tag === "mj-all" && a.attrs["font-family"] && (e.fontFamily = a.attrs["font-family"]);
11
+ for (const a of o.children) {
12
+ const l = e.attributeDefaults;
13
+ if (a.tag === "mj-all")
14
+ Object.assign(l.all, a.attrs);
15
+ else if (a.tag === "mj-class") {
16
+ const { name: s, ...c } = a.attrs;
17
+ s && (l.classes[s] = { ...l.classes[s], ...c });
18
+ } else
19
+ l.tags[a.tag] = { ...l.tags[a.tag], ...a.attrs };
20
+ }
21
+ e.attributeDefaults.all["font-family"] && (e.fontFamily = e.attributeDefaults.all["font-family"]);
22
+ break;
23
+ case "mj-style":
24
+ o.attrs.inline !== "inline" && o.text.trim() && r.push(o.text.trim());
13
25
  break;
14
26
  }
15
- return e;
27
+ return r.length > 0 && (e.css = r.join(`
28
+ `)), e;
16
29
  }
17
- function u(t, n = 0) {
30
+ function f(t, n = 0) {
18
31
  if (!t)
19
32
  return { top: n, right: n, bottom: n, left: n };
20
- const e = t.trim().split(/\s+/).map(A);
33
+ const e = t.trim().split(/\s+/).map(L);
21
34
  switch (e.length) {
22
35
  case 1:
23
36
  return { top: e[0], right: e[0], bottom: e[0], left: e[0] };
@@ -31,202 +44,244 @@ function u(t, n = 0) {
31
44
  return { top: n, right: n, bottom: n, left: n };
32
45
  }
33
46
  }
34
- function A(t) {
47
+ function L(t) {
35
48
  const n = parseFloat(t);
36
49
  return isNaN(n) ? 0 : n;
37
50
  }
38
- function r(t, n, e = "") {
51
+ function i(t, n, e = "") {
39
52
  return t[n] ?? e;
40
53
  }
41
- function f(t, n, e = 0) {
42
- const o = t[n];
43
- if (o === void 0 || o === "") return e;
44
- const a = parseFloat(o);
45
- return isNaN(a) ? e : a;
54
+ function b(t, n, e = 0) {
55
+ const r = t[n];
56
+ if (r === void 0 || r === "") return e;
57
+ const o = parseFloat(r);
58
+ return isNaN(o) ? e : o;
46
59
  }
47
- function T(t, n) {
60
+ function O(t, n) {
48
61
  return {
49
- id: p(),
62
+ id: m(),
50
63
  type: "text",
51
64
  values: {
52
65
  content: n,
53
- padding: u(r(t, "padding"), 10),
54
- lineHeight: r(t, "line-height", "1.5"),
55
- textAlign: r(t, "align", "left")
66
+ padding: f(i(t, "padding"), 10),
67
+ lineHeight: i(t, "line-height", "1.5"),
68
+ textAlign: i(t, "align", "left"),
69
+ cssClass: i(t, "css-class") || void 0
56
70
  }
57
71
  };
58
72
  }
59
- function B(t) {
60
- const n = r(t, "width"), e = n && parseInt(n, 10) || "auto";
73
+ function U(t) {
74
+ const n = i(t, "width"), e = n && parseInt(n, 10) || "auto";
61
75
  return {
62
- id: p(),
76
+ id: m(),
63
77
  type: "image",
64
78
  values: {
65
- src: r(t, "src"),
66
- alt: r(t, "alt"),
79
+ src: i(t, "src"),
80
+ alt: i(t, "alt"),
67
81
  width: e,
68
- href: r(t, "href") || void 0,
69
- padding: u(r(t, "padding"), 10),
70
- alignment: r(t, "align", "center"),
71
- borderRadius: f(t, "border-radius", 0)
82
+ href: i(t, "href") || void 0,
83
+ padding: f(i(t, "padding"), 10),
84
+ alignment: i(t, "align", "center"),
85
+ borderRadius: b(t, "border-radius", 0),
86
+ cssClass: i(t, "css-class") || void 0
72
87
  }
73
88
  };
74
89
  }
75
- function N(t, n) {
76
- const e = n.trim(), o = /^<p[\s>]/i.test(e) ? e : `<p>${e}</p>`;
90
+ function W(t, n) {
91
+ const e = n.trim(), r = /^<p[\s>]/i.test(e) ? e : `<p>${e}</p>`;
77
92
  return {
78
- id: p(),
93
+ id: m(),
79
94
  type: "button",
80
95
  values: {
81
- content: o,
82
- href: r(t, "href", "#"),
83
- backgroundColor: r(t, "background-color", "#3b82f6"),
84
- textColor: r(t, "color", "#ffffff"),
85
- borderRadius: f(t, "border-radius", 4),
86
- padding: u(r(t, "padding"), 10),
87
- innerPadding: u(r(t, "inner-padding"), 12),
88
- fontSize: f(t, "font-size", 16),
89
- fontWeight: r(t, "font-weight", "600"),
90
- alignment: r(t, "align", "center"),
91
- fullWidth: r(t, "width") === "100%"
96
+ content: r,
97
+ href: i(t, "href", "#"),
98
+ backgroundColor: i(t, "background-color", "#3b82f6"),
99
+ textColor: i(t, "color", "#ffffff"),
100
+ borderRadius: b(t, "border-radius", 4),
101
+ padding: f(i(t, "padding"), 10),
102
+ innerPadding: f(i(t, "inner-padding"), 12),
103
+ fontSize: b(t, "font-size", 16),
104
+ fontWeight: i(t, "font-weight", "600"),
105
+ alignment: i(t, "align", "center"),
106
+ fullWidth: i(t, "width") === "100%",
107
+ cssClass: i(t, "css-class") || void 0
92
108
  }
93
109
  };
94
110
  }
95
- function W(t) {
111
+ function P(t) {
96
112
  return {
97
- id: p(),
113
+ id: m(),
98
114
  type: "divider",
99
115
  values: {
100
- borderColor: r(t, "border-color", "#e2e8f0"),
101
- borderWidth: f(t, "border-width", 1),
102
- borderStyle: r(t, "border-style", "solid"),
103
- padding: u(r(t, "padding"), 10),
104
- width: r(t, "width", "100%")
116
+ borderColor: i(t, "border-color", "#e2e8f0"),
117
+ borderWidth: b(t, "border-width", 1),
118
+ borderStyle: i(t, "border-style", "solid"),
119
+ padding: f(i(t, "padding"), 10),
120
+ width: i(t, "width", "100%")
105
121
  }
106
122
  };
107
123
  }
108
- function $(t) {
124
+ function q(t) {
109
125
  return {
110
- id: p(),
126
+ id: m(),
111
127
  type: "spacer",
112
128
  values: {
113
- height: f(t, "height", 20)
129
+ height: b(t, "height", 20)
114
130
  }
115
131
  };
116
132
  }
117
- const D = ["facebook", "twitter", "instagram", "linkedin", "youtube", "tiktok"];
118
- function F(t) {
133
+ const G = ["facebook", "twitter", "instagram", "linkedin", "youtube", "tiktok"];
134
+ function X(t) {
119
135
  const n = t.toLowerCase();
120
- for (const e of D)
136
+ for (const e of G)
121
137
  if (n.includes(e)) return e;
122
138
  return "custom";
123
139
  }
124
- function I(t, n) {
125
- const e = n.map((o) => {
126
- const c = {
127
- type: F(r(o.attrs, "name", "custom")),
128
- href: r(o.attrs, "href", "#"),
129
- label: o.innerText.trim() || void 0
130
- }, s = r(o.attrs, "src");
131
- return s && (c.iconUrl = s), c;
140
+ function M(t, n) {
141
+ const e = n.map((r) => {
142
+ const a = {
143
+ type: X(i(r.attrs, "name", "custom")),
144
+ href: i(r.attrs, "href", "#"),
145
+ label: r.innerText.trim() || void 0
146
+ }, l = i(r.attrs, "src");
147
+ return l && (a.iconUrl = l), a;
132
148
  });
133
149
  return {
134
- id: p(),
150
+ id: m(),
135
151
  type: "social",
136
152
  values: {
137
153
  icons: e,
138
- iconSize: f(t, "icon-size", 32),
139
- spacing: f(t, "icon-padding", 8),
140
- alignment: r(t, "align", "center"),
141
- padding: u(r(t, "padding"), 10)
154
+ iconSize: b(t, "icon-size", 32),
155
+ spacing: b(t, "icon-padding", 8),
156
+ alignment: i(t, "align", "center"),
157
+ padding: f(i(t, "padding"), 10)
142
158
  }
143
159
  };
144
160
  }
145
- function P(t) {
161
+ function K(t) {
146
162
  const n = t.match(/^<div\s+style="padding:\s*([^"]*)">([\s\S]*)<\/div>$/);
147
163
  return n ? {
148
- id: p(),
164
+ id: m(),
149
165
  type: "html",
150
166
  values: {
151
167
  content: n[2],
152
- padding: u(n[1], 0)
168
+ padding: f(n[1], 0)
153
169
  }
154
170
  } : {
155
- id: p(),
171
+ id: m(),
156
172
  type: "html",
157
173
  values: {
158
174
  content: t,
159
- padding: u(void 0, 0)
175
+ padding: f(void 0, 0)
160
176
  }
161
177
  };
162
178
  }
163
- function z(t, n) {
164
- const e = n.map((o) => {
179
+ const V = {
180
+ align: "left",
181
+ border: "none",
182
+ cellpadding: "0",
183
+ cellspacing: "0",
184
+ color: "#000000",
185
+ "font-family": "Ubuntu, Helvetica, Arial, sans-serif",
186
+ "font-size": "13px",
187
+ "line-height": "22px",
188
+ padding: "10px 25px",
189
+ "table-layout": "auto",
190
+ width: "100%"
191
+ };
192
+ function Y(t, n) {
193
+ const e = { ...V, ...t }, r = e.width.endsWith("%") || e.width === "auto" ? e.width : String(parseInt(e.width, 10)), o = parseFloat(e.cellspacing.replace(/[^\d.]/g, "")), a = [
194
+ `color:${e.color}`,
195
+ `font-family:${e["font-family"]}`,
196
+ `font-size:${e["font-size"]}`,
197
+ `line-height:${e["line-height"]}`,
198
+ `table-layout:${e["table-layout"]}`,
199
+ `width:${e.width}`,
200
+ `border:${e.border}`,
201
+ ...o > 0 ? ["border-collapse:separate"] : []
202
+ ].map((s) => `${s};`).join(""), l = [];
203
+ return e.align !== "left" && l.push(`align="${j(e.align)}"`), l.push(`cellpadding="${j(e.cellpadding)}"`, `cellspacing="${j(e.cellspacing)}"`), t.role && l.push(`role="${j(t.role)}"`), l.push(`width="${j(r)}"`, 'border="0"', `style="${j(a)}"`), {
204
+ id: m(),
205
+ type: "html",
206
+ values: {
207
+ content: `<table ${l.join(" ")}>${n.trim()}</table>`,
208
+ padding: f(i(e, "padding"), 0)
209
+ }
210
+ };
211
+ }
212
+ function j(t) {
213
+ return t.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
214
+ }
215
+ function Z(t, n) {
216
+ const e = i(t, "base-url"), r = n.map((o) => {
165
217
  const a = {
166
- href: r(o.attrs, "href", "#"),
218
+ href: e + i(o.attrs, "href", "#"),
167
219
  text: o.innerText.trim() || "Link"
168
- }, c = r(o.attrs, "color");
169
- c && (a.color = c);
170
- const s = r(o.attrs, "font-weight");
220
+ }, l = i(o.attrs, "color");
221
+ l && (a.color = l);
222
+ const s = i(o.attrs, "font-weight");
171
223
  s && (a.fontWeight = s);
172
- const i = r(o.attrs, "text-decoration");
173
- i && (a.textDecoration = i);
174
- const d = r(o.attrs, "padding");
175
- return d && (a.padding = d), a;
224
+ const c = i(o.attrs, "text-decoration");
225
+ c && (a.textDecoration = c);
226
+ const g = i(o.attrs, "padding");
227
+ return g && (a.padding = g), a;
176
228
  });
177
229
  return {
178
- id: p(),
230
+ id: m(),
179
231
  type: "navbar",
180
232
  values: {
181
- links: e,
182
- hamburger: r(t, "hamburger", "hamburger"),
183
- alignment: r(t, "align", "center"),
184
- padding: u(r(t, "padding"), 10),
185
- linkColor: r(t, "ico-color", "#000000"),
186
- linkFontSize: f(t, "font-size", 14),
187
- linkPadding: r(t, "link-padding", "10px 15px")
233
+ links: r,
234
+ hamburger: i(t, "hamburger", "hamburger"),
235
+ alignment: i(t, "align", "center"),
236
+ padding: f(i(t, "padding"), 10),
237
+ linkColor: i(t, "ico-color", "#000000"),
238
+ linkFontSize: b(t, "font-size", 14),
239
+ linkPadding: i(t, "link-padding", "10px 15px")
188
240
  }
189
241
  };
190
242
  }
191
- function w(t, n) {
192
- const e = t.attrs, o = [];
193
- for (const a of t.children) {
194
- const c = H(a, n);
195
- c && o.push(c);
243
+ function T(t, n) {
244
+ const e = t.attrs, r = [];
245
+ for (const o of t.children) {
246
+ const a = J(o, n);
247
+ a && r.push(a);
196
248
  }
197
249
  return {
198
- id: p(),
250
+ id: m(),
199
251
  type: "column",
200
252
  attributes: {
201
- backgroundColor: r(e, "background-color") || void 0,
202
- padding: u(r(e, "padding"), 0),
203
- borderRadius: f(e, "border-radius", 0) || void 0,
204
- verticalAlign: r(e, "vertical-align", "top")
253
+ backgroundColor: i(e, "background-color") || void 0,
254
+ padding: f(i(e, "padding"), 0),
255
+ borderRadius: b(e, "border-radius", 0) || void 0,
256
+ verticalAlign: i(e, "vertical-align", "top"),
257
+ cssClass: i(e, "css-class") || void 0
205
258
  },
206
- blocks: o
259
+ blocks: r
207
260
  };
208
261
  }
209
- function H(t, n) {
262
+ function J(t, n) {
210
263
  switch (t.tag) {
211
264
  case "mj-text":
212
- return T(t.attrs, t.text);
265
+ return O(t.attrs, t.text);
213
266
  case "mj-image":
214
- return B(t.attrs);
267
+ return U(t.attrs);
215
268
  case "mj-button":
216
- return N(t.attrs, t.text);
269
+ return W(t.attrs, t.text);
217
270
  case "mj-divider":
218
- return W(t.attrs);
271
+ return P(t.attrs);
219
272
  case "mj-spacer":
220
- return $(t.attrs);
273
+ return q(t.attrs);
221
274
  case "mj-social": {
222
- const e = t.children.filter((o) => o.tag === "mj-social-element").map((o) => ({ attrs: o.attrs, innerText: o.text }));
223
- return I(t.attrs, e);
275
+ const e = t.children.filter((r) => r.tag === "mj-social-element").map((r) => ({ attrs: r.attrs, innerText: r.text }));
276
+ return M(t.attrs, e);
224
277
  }
225
278
  case "mj-raw":
226
- return P(t.text);
279
+ return K(t.text);
280
+ case "mj-table":
281
+ return Y(t.attrs, t.text);
227
282
  case "mj-navbar": {
228
- const e = t.children.filter((o) => o.tag === "mj-navbar-link").map((o) => ({ attrs: o.attrs, innerText: o.text }));
229
- return z(t.attrs, e);
283
+ const e = t.children.filter((r) => r.tag === "mj-navbar-link").map((r) => ({ attrs: r.attrs, innerText: r.text }));
284
+ return Z(t.attrs, e);
230
285
  }
231
286
  default:
232
287
  return n.push({
@@ -235,130 +290,290 @@ function H(t, n) {
235
290
  }), null;
236
291
  }
237
292
  }
238
- function v(t, n) {
239
- const e = t.attrs, o = [];
240
- for (const i of t.children)
241
- if (i.tag === "mj-column")
242
- o.push(w(i, n));
243
- else if (i.tag === "mj-group")
244
- for (const d of i.children)
245
- d.tag === "mj-column" && o.push(w(d, n));
293
+ function A(t, n) {
294
+ const e = t.attrs, r = [];
295
+ for (const s of t.children)
296
+ if (s.tag === "mj-column")
297
+ r.push(T(s, n));
298
+ else if (s.tag === "mj-group")
299
+ for (const c of s.children)
300
+ c.tag === "mj-column" && r.push(T(c, n));
246
301
  else
247
302
  n.push({
248
- message: `Unexpected section child: ${i.tag}`,
249
- tag: i.tag
303
+ message: `Unexpected section child: ${s.tag}`,
304
+ tag: s.tag
250
305
  });
251
- o.length === 0 && o.push({
252
- id: p(),
306
+ r.length === 0 && r.push({
307
+ id: m(),
253
308
  type: "column",
254
309
  attributes: {
255
- padding: u(void 0, 0),
310
+ padding: f(void 0, 0),
256
311
  verticalAlign: "top"
257
312
  },
258
313
  blocks: []
259
314
  });
260
- const a = R(o), s = r(e, "full-width") === "full-width";
315
+ const o = Q(r), l = i(e, "full-width") === "full-width";
261
316
  return {
262
- id: p(),
317
+ id: m(),
263
318
  type: "row",
264
319
  attributes: {
265
- backgroundColor: r(e, "background-color") || void 0,
266
- backgroundImage: r(e, "background-url") || void 0,
267
- padding: u(r(e, "padding"), 0),
268
- fullWidth: s
320
+ backgroundColor: i(e, "background-color") || void 0,
321
+ backgroundImage: i(e, "background-url") || void 0,
322
+ padding: f(i(e, "padding"), 0),
323
+ fullWidth: l,
324
+ cssClass: i(e, "css-class") || void 0
269
325
  },
270
- columns: o,
271
- columnRatios: a,
326
+ columns: r,
327
+ columnRatios: o,
272
328
  locked: !1
273
329
  };
274
330
  }
275
- function R(t, n) {
276
- const e = t.length, o = Math.floor(12 / e);
277
- return t.map(() => o);
331
+ function Q(t, n) {
332
+ const e = t.length, r = Math.floor(12 / e);
333
+ return t.map(() => r);
278
334
  }
279
- function O(t, n) {
335
+ function tt(t, n, e) {
280
336
  return {
281
- id: p(),
337
+ id: m(),
282
338
  type: "hero",
283
339
  values: {
284
- backgroundUrl: r(t, "background-url"),
285
- backgroundPosition: r(t, "background-position", "center center"),
286
- mode: r(t, "mode", "fluid-height"),
287
- width: f(t, "width", 600),
288
- height: f(t, "height", 400),
289
- verticalAlign: r(t, "vertical-align", "middle"),
290
- padding: u(r(t, "padding"), 0),
291
- innerPadding: u(void 0, 20),
292
- backgroundColor: r(t, "background-color", "#ffffff"),
340
+ backgroundUrl: i(t, "background-url"),
341
+ backgroundPosition: i(t, "background-position", "center center"),
342
+ mode: i(t, "mode", "fluid-height"),
343
+ width: b(t, "width", 600),
344
+ height: b(t, "height", 400),
345
+ verticalAlign: i(t, "vertical-align", "middle"),
346
+ padding: f(i(t, "padding"), 0),
347
+ innerPadding: f(e, 20),
348
+ backgroundColor: i(t, "background-color", "#ffffff"),
293
349
  content: n
294
350
  }
295
351
  };
296
352
  }
297
- function U(t, n) {
298
- const e = f(t.attrs, "width", 600), o = r(t.attrs, "background-color", "#f4f4f5"), a = [];
299
- let c;
300
- const s = (i) => (c && (i.attributes.condition = c, c = void 0), i);
301
- for (const i of t.children)
302
- switch (i.tag) {
353
+ const et = [
354
+ ["font-style", "font-style"],
355
+ ["font-weight", "font-weight"],
356
+ ["letter-spacing", "letter-spacing"],
357
+ ["line-height", "line-height"],
358
+ ["text-align", "align"],
359
+ ["text-decoration", "text-decoration"],
360
+ ["text-transform", "text-transform"],
361
+ ["height", "height"]
362
+ ], nt = "1.5";
363
+ function E(t, n, e) {
364
+ const r = et.filter(([o, a]) => t[a] && !(o === "line-height" && t[a] === nt)).concat(!e && t.padding ? [["padding", "padding"]] : []).map(([o, a]) => `${o}:${t[a]};`).join("");
365
+ return r ? `<div style="${w(r)}">${n}</div>` : e ? n : `<div>${n}</div>`;
366
+ }
367
+ const rt = {
368
+ align: "center",
369
+ "background-color": "#414141",
370
+ border: "none",
371
+ "border-radius": "3px",
372
+ color: "#ffffff",
373
+ "font-family": "Ubuntu, Helvetica, Arial, sans-serif",
374
+ "font-size": "13px",
375
+ "font-weight": "normal",
376
+ "inner-padding": "10px 25px",
377
+ "line-height": "120%",
378
+ padding: "10px 25px",
379
+ target: "_blank",
380
+ "text-decoration": "none",
381
+ "text-transform": "none",
382
+ "vertical-align": "middle"
383
+ };
384
+ function ot(t, n) {
385
+ const e = { ...rt, ...t }, r = e["background-color"], o = `border:${e.border};border-radius:${e["border-radius"]};cursor:auto;mso-padding-alt:${e["inner-padding"]};background:${r};`, a = `display:inline-block;background:${r};color:${e.color};font-family:${e["font-family"]};font-size:${e["font-size"]};font-weight:${e["font-weight"]};line-height:${e["line-height"]};margin:0;text-decoration:${e["text-decoration"]};text-transform:${e["text-transform"]};padding:${e["inner-padding"]};mso-padding-alt:0px;border-radius:${e["border-radius"]};`, l = e.href ? `<a href="${w(e.href)}" target="${w(e.target)}" style="${w(a)}">${n.trim()}</a>` : `<p style="${w(a)}">${n.trim()}</p>`;
386
+ return `<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"><tr><td align="${w(e.align)}" style="padding:${w(e.padding)};"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;"><tr><td align="center"${r === "none" ? "" : ` bgcolor="${w(r)}"`} role="presentation" valign="${w(e["vertical-align"])}" style="${w(o)}">${l}</td></tr></table></td></tr></table>`;
387
+ }
388
+ function w(t) {
389
+ return t.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
390
+ }
391
+ function it(t, n) {
392
+ const e = b(t.attrs, "width", 600), r = i(t.attrs, "background-color", "#f4f4f5"), o = [];
393
+ let a;
394
+ const l = (s) => (a && (s.attributes.condition = a, a = void 0), s);
395
+ for (const s of t.children)
396
+ switch (s.tag) {
303
397
  case "mj-raw": {
304
- const d = /\{\{#if\s+([^}]+?)\s*\}\}/.exec(i.text ?? "");
305
- d && (c = d[1].trim());
398
+ const c = /\{\{#if\s+([^}]+?)\s*\}\}/.exec(s.text ?? "");
399
+ c && (a = c[1].trim());
306
400
  break;
307
401
  }
308
402
  case "mj-section":
309
- a.push(s(v(i, n)));
403
+ o.push(l(A(s, n)));
310
404
  break;
311
405
  case "mj-hero": {
312
- const d = _(i), l = O(i.attrs, d), m = {
313
- id: p(),
406
+ const c = at(s, n), g = tt(s.attrs, c.content, c.innerPadding), p = {
407
+ id: m(),
314
408
  type: "column",
315
409
  attributes: {
316
- padding: u(void 0, 0),
410
+ padding: f(void 0, 0),
317
411
  verticalAlign: "top"
318
412
  },
319
- blocks: [l]
320
- }, g = {
321
- id: p(),
413
+ blocks: [g]
414
+ }, d = {
415
+ id: m(),
322
416
  type: "row",
323
417
  attributes: {
324
- padding: u(void 0, 0),
418
+ padding: f(void 0, 0),
325
419
  fullWidth: !1
326
420
  },
327
- columns: [m],
421
+ columns: [p],
328
422
  columnRatios: [12],
329
423
  locked: !1
330
424
  };
331
- a.push(s(g));
425
+ o.push(l(d));
332
426
  break;
333
427
  }
334
428
  case "mj-wrapper":
335
- for (const d of i.children)
336
- d.tag === "mj-section" && a.push(s(v(d, n)));
429
+ n.push({
430
+ message: "mj-wrapper styling (padding, background-color) was dropped: the document model has no wrapper; its sections were imported unwrapped",
431
+ tag: "mj-wrapper"
432
+ });
433
+ for (const c of s.children)
434
+ c.tag === "mj-section" && o.push(l(A(c, n)));
337
435
  break;
338
436
  default:
339
437
  n.push({
340
- message: `Unknown body child element: ${i.tag}`,
341
- tag: i.tag
438
+ message: `Unknown body child element: ${s.tag}`,
439
+ tag: s.tag
342
440
  });
343
441
  break;
344
442
  }
345
- return { width: e, backgroundColor: o, rows: a };
443
+ return { width: e, backgroundColor: r, rows: o };
346
444
  }
347
- function _(t) {
348
- const n = [];
445
+ function at(t, n) {
446
+ const [e] = t.children;
447
+ if (t.children.length === 1 && e.tag === "mj-text")
448
+ return { content: E(e.attrs, e.text, !0), innerPadding: e.attrs.padding };
449
+ const r = [];
450
+ for (const o of t.children)
451
+ o.tag === "mj-text" ? r.push(E(o.attrs, o.text, !1)) : o.tag === "mj-button" ? r.push(ot(o.attrs, o.text)) : n.push({ message: `Unsupported mj-hero child element: ${o.tag}`, tag: o.tag });
452
+ return { content: r.join("") || "<p>Hero Content</p>" };
453
+ }
454
+ const st = /* @__PURE__ */ new Set(["mj-section", "mj-column", "mj-text", "mj-button", "mj-image"]);
455
+ function R(t, n, e) {
456
+ const { "mj-class": r = "", ...o } = t.attrs, a = r.split(/\s+/).filter(Boolean).reduce((s, c) => {
457
+ const g = n.classes[c] ?? {}, p = s["css-class"] && g["css-class"] ? { "css-class": `${s["css-class"]} ${g["css-class"]}` } : {};
458
+ return { ...s, ...g, ...p };
459
+ }, {});
460
+ t.attrs = { ...n.all, ...n.tags[t.tag], ...a, ...o };
461
+ const l = t.attrs["css-class"];
462
+ l && !st.has(t.tag) && e.push({ message: `css-class "${l}" on <${t.tag}> was dropped`, tag: t.tag });
463
+ for (const s of t.children)
464
+ R(s, n, e);
465
+ }
466
+ const D = /* @__PURE__ */ new Set([
467
+ "address",
468
+ "article",
469
+ "aside",
470
+ "blockquote",
471
+ "center",
472
+ "dd",
473
+ "div",
474
+ "dl",
475
+ "dt",
476
+ "figcaption",
477
+ "figure",
478
+ "footer",
479
+ "form",
480
+ "h1",
481
+ "h2",
482
+ "h3",
483
+ "h4",
484
+ "h5",
485
+ "h6",
486
+ "header",
487
+ "hr",
488
+ "li",
489
+ "main",
490
+ "nav",
491
+ "ol",
492
+ "p",
493
+ "pre",
494
+ "section",
495
+ "table",
496
+ "tbody",
497
+ "td",
498
+ "tfoot",
499
+ "th",
500
+ "thead",
501
+ "tr",
502
+ "ul"
503
+ ]), B = /* @__PURE__ */ new Set([
504
+ "area",
505
+ "base",
506
+ "br",
507
+ "col",
508
+ "embed",
509
+ "hr",
510
+ "img",
511
+ "input",
512
+ "link",
513
+ "meta",
514
+ "source",
515
+ "track",
516
+ "wbr"
517
+ ]), lt = "14px", ct = "#000000";
518
+ function z(t, n) {
519
+ if (t.tag === "mj-text") {
520
+ const { color: e, "font-size": r, "font-family": o } = t.attrs, a = [];
521
+ e && e.toLowerCase() !== ct && a.push(`color: ${e}`), r && r !== lt && a.push(`font-size: ${r}`), o && o !== n && a.push(`font-family: ${o}`), a.length > 0 && (t.text = dt(t.text, `<span style="${ut(a.join("; "))}">`));
522
+ return;
523
+ }
349
524
  for (const e of t.children)
350
- (e.tag === "mj-text" || e.tag === "mj-button") && n.push(e.text);
351
- return n.join("") || "<p>Hero Content</p>";
525
+ z(e, n);
352
526
  }
353
- function E(t) {
354
- const n = { tag: "root", attrs: {}, children: [], text: "" }, e = [n], o = /* @__PURE__ */ new Set([
527
+ function dt(t, n) {
528
+ const e = [];
529
+ let r = -1, o = -1, a = !1, l = 0;
530
+ const s = () => {
531
+ r >= 0 && a && e.push([r, n], [o, "</span>"]), r = -1, a = !1;
532
+ }, c = (d, h) => {
533
+ r < 0 && (r = d), o = h;
534
+ }, g = new _({
535
+ onopentag(d) {
536
+ if (l === 0 && D.has(d)) {
537
+ s();
538
+ return;
539
+ }
540
+ c(g.startIndex, g.endIndex + 1), B.has(d) ? a = !0 : l++;
541
+ },
542
+ onclosetag(d, h) {
543
+ if (!B.has(d)) {
544
+ if (l === 0) {
545
+ D.has(d) && s();
546
+ return;
547
+ }
548
+ l--, h || (o = g.endIndex + 1);
549
+ }
550
+ },
551
+ ontext(d) {
552
+ r < 0 && !d.trim() || (c(g.startIndex, g.endIndex + 1), d.trim() && (a = !0));
553
+ },
554
+ oncomment() {
555
+ r >= 0 && (o = g.endIndex + 1);
556
+ }
557
+ }, { recognizeSelfClosing: !0, lowerCaseTags: !0 });
558
+ g.write(t), g.end(), s();
559
+ let p = t;
560
+ for (const [d, h] of e.reverse())
561
+ p = p.slice(0, d) + h + p.slice(d);
562
+ return p;
563
+ }
564
+ function ut(t) {
565
+ return t.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
566
+ }
567
+ function gt(t) {
568
+ const n = { tag: "root", attrs: {}, children: [], text: "" }, e = [n], r = /* @__PURE__ */ new Set([
355
569
  "mj-text",
356
570
  "mj-button",
357
571
  "mj-raw",
358
572
  "mj-preview",
359
573
  "mj-social-element",
360
- "mj-navbar-link"
361
- ]), a = /* @__PURE__ */ new Set([
574
+ "mj-navbar-link",
575
+ "mj-table"
576
+ ]), o = /* @__PURE__ */ new Set([
362
577
  "mj-image",
363
578
  "mj-divider",
364
579
  "mj-spacer",
@@ -366,98 +581,120 @@ function E(t) {
366
581
  "mj-class",
367
582
  "mj-font",
368
583
  "mj-breakpoint"
369
- ]);
370
- let c = null, s = "", i = 0;
371
- const d = new C({
372
- onopentag(l, m) {
373
- if (c) {
374
- const k = Object.entries(m).map(([x, y]) => `${x}="${y}"`).join(" ");
375
- s += k ? `<${l} ${k}>` : `<${l}>`, i++;
584
+ ]), a = /* @__PURE__ */ new Set([
585
+ "area",
586
+ "base",
587
+ "br",
588
+ "col",
589
+ "embed",
590
+ "hr",
591
+ "img",
592
+ "input",
593
+ "link",
594
+ "meta",
595
+ "source",
596
+ "track",
597
+ "wbr"
598
+ ]), l = /* @__PURE__ */ new Set(["mj-text", "mj-button", "mj-raw"]), s = /* @__PURE__ */ new Set(["style", "script"]), c = (u) => u.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), g = (u) => u.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
599
+ let p = null, d = "", h = 0, x = !1;
600
+ const y = new _({
601
+ onopentag(u, $) {
602
+ if (p) {
603
+ const N = l.has(p.node.tag), S = Object.entries($).map(([F, C]) => `${F}="${N ? g(C) : C}"`).join(" ");
604
+ d += S ? `<${u} ${S}>` : `<${u}>`, a.has(u) || h++, s.has(u) && (x = !0);
376
605
  return;
377
606
  }
378
- const g = { tag: l, attrs: m, children: [], text: "" };
379
- e[e.length - 1].children.push(g), !a.has(l) && (e.push(g), o.has(l) && (c = { node: g, depth: 0 }, s = "", i = 0));
607
+ const k = { tag: u, attrs: $, children: [], text: "" };
608
+ e[e.length - 1].children.push(k), !o.has(u) && (e.push(k), r.has(u) && (p = { node: k, depth: 0 }, d = "", h = 0));
380
609
  },
381
- ontext(l) {
382
- if (c) {
383
- s += l;
610
+ ontext(u) {
611
+ if (p) {
612
+ const k = l.has(p.node.tag) && !x;
613
+ d += k ? c(u) : u;
384
614
  return;
385
615
  }
386
- const m = e[e.length - 1];
387
- m.text += l;
616
+ const $ = e[e.length - 1];
617
+ $.text += u;
388
618
  },
389
- onclosetag(l) {
390
- if (c) {
391
- if (i > 0) {
392
- s += `</${l}>`, i--;
619
+ onclosetag(u) {
620
+ if (p) {
621
+ if (a.has(u)) return;
622
+ if (h > 0) {
623
+ d += `</${u}>`, h--, s.has(u) && (x = !1);
393
624
  return;
394
625
  }
395
- c.node.text = s, c = null, s = "", i = 0, e.length > 1 && e[e.length - 1].tag === l && e.pop();
626
+ p.node.text = d, p = null, d = "", h = 0, e.length > 1 && e[e.length - 1].tag === u && e.pop();
396
627
  return;
397
628
  }
398
- a.has(l) || e.length > 1 && e[e.length - 1].tag === l && e.pop();
629
+ o.has(u) || e.length > 1 && e[e.length - 1].tag === u && e.pop();
630
+ },
631
+ oncomment(u) {
632
+ p && (d += `<!--${u}-->`);
399
633
  }
400
634
  }, {
401
635
  recognizeSelfClosing: !0,
402
636
  lowerCaseTags: !0,
403
637
  lowerCaseAttributeNames: !0
404
638
  });
405
- return d.write(t), d.end(), n;
639
+ return y.write(t), y.end(), n;
406
640
  }
407
- function b(t, n) {
641
+ function v(t, n) {
408
642
  if (t.tag === n) return t;
409
643
  for (const e of t.children) {
410
- const o = b(e, n);
411
- if (o) return o;
644
+ const r = v(e, n);
645
+ if (r) return r;
412
646
  }
413
647
  }
414
- function K(t, n) {
415
- const e = [], o = E(t), a = b(o, "mjml");
416
- if (!a)
648
+ function mt(t, n) {
649
+ const e = [], r = gt(t), o = v(r, "mjml");
650
+ if (!o)
417
651
  return e.push({ message: "No <mjml> root element found" }), {
418
- document: j(),
652
+ document: I(),
419
653
  warnings: e
420
654
  };
421
- const c = b(a, "mj-head"), s = b(a, "mj-body");
422
- let i = {};
423
- if (c && (i = S(
424
- c.children.map((g) => ({
425
- tag: g.tag,
426
- attrs: g.attrs,
427
- children: g.children.map((h) => ({
428
- tag: h.tag,
429
- attrs: h.attrs,
655
+ const a = v(o, "mj-head"), l = v(o, "mj-body");
656
+ let s = { attributeDefaults: { all: {}, tags: {}, classes: {} } };
657
+ if (a && (s = H(
658
+ a.children.map((h) => ({
659
+ tag: h.tag,
660
+ attrs: h.attrs,
661
+ children: h.children.map((x) => ({
662
+ tag: x.tag,
663
+ attrs: x.attrs,
430
664
  children: [],
431
- text: h.text
665
+ text: x.text
432
666
  })),
433
- text: g.text
667
+ text: h.text
434
668
  }))
435
- )), !s)
669
+ )), !l)
436
670
  return e.push({ message: "No <mj-body> element found" }), {
437
- document: j(),
671
+ document: I(),
438
672
  warnings: e
439
673
  };
440
- const d = U(s, e), l = (/* @__PURE__ */ new Date()).toISOString();
674
+ const c = s.fontFamily ?? "Arial, Helvetica, sans-serif";
675
+ R(l, s.attributeDefaults, e), z(l, c);
676
+ const g = it(l, e), p = (/* @__PURE__ */ new Date()).toISOString();
441
677
  return { document: {
442
678
  version: "1.0",
443
679
  metadata: {
444
680
  name: "Imported Template",
445
- previewText: i.previewText,
446
- createdAt: l,
447
- updatedAt: l
681
+ previewText: s.previewText,
682
+ createdAt: p,
683
+ updatedAt: p
448
684
  },
449
685
  body: {
450
686
  attributes: {
451
- width: d.width,
452
- backgroundColor: d.backgroundColor,
453
- fontFamily: i.fontFamily ?? "Arial, Helvetica, sans-serif",
454
- contentAlignment: "center"
687
+ width: g.width,
688
+ backgroundColor: g.backgroundColor,
689
+ fontFamily: c,
690
+ contentAlignment: "center",
691
+ css: s.css
455
692
  },
456
- rows: d.rows
693
+ rows: g.rows
457
694
  }
458
695
  }, warnings: e };
459
696
  }
460
- function j() {
697
+ function I() {
461
698
  const t = (/* @__PURE__ */ new Date()).toISOString();
462
699
  return {
463
700
  version: "1.0",
@@ -478,5 +715,5 @@ function j() {
478
715
  };
479
716
  }
480
717
  export {
481
- K as mjmlToDocument
718
+ mt as mjmlToDocument
482
719
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lit-pigeon/parser-mjml",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "MJML-to-PigeonDocument parser for Pigeon email editor",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -20,13 +20,15 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "htmlparser2": "^9.1.0",
23
- "@lit-pigeon/core": "^0.3.2"
23
+ "@lit-pigeon/core": "^0.3.3"
24
24
  },
25
25
  "devDependencies": {
26
+ "mjml": "^4.15.0",
26
27
  "typescript": "^5.5.0",
27
28
  "vite": "^6.0.0",
28
29
  "vite-plugin-dts": "^4.0.0",
29
- "vitest": "^3.0.0"
30
+ "vitest": "^3.0.0",
31
+ "@lit-pigeon/renderer-mjml": "^0.2.4"
30
32
  },
31
33
  "publishConfig": {
32
34
  "access": "public"