@bgscore/report-generator
Version:
Generate reports in Excel or PDF format from HTML or template files (Excel, DOCX, etc). Supports dynamic data injection, styling, and layout rendering.
8 lines (7 loc) • 16.3 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _vm2 = require('vm2');var _acorn = require('acorn'); var _acorn2 = _interopRequireDefault(_acorn);var _acornwalk = require('acorn-walk'); var _acornwalk2 = _interopRequireDefault(_acornwalk);var _handlebars = require('handlebars'); var _handlebars2 = _interopRequireDefault(_handlebars);var _sha256 = require('crypto-js/sha256'); var _sha2562 = _interopRequireDefault(_sha256);var _enchex = require('crypto-js/enc-hex'); var _enchex2 = _interopRequireDefault(_enchex);var _colord = require('colord');var _imagesize = require('image-size'); var _imagesize2 = _interopRequireDefault(_imagesize);var _axios = require('axios'); var _axios2 = _interopRequireDefault(_axios);function P(e){return!(e==null||typeof e=="string"&&e.trim()===""||Array.isArray(e)&&e.length===0||typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.keys(e).length===0)}var J=(e="")=>_sha2562.default.call(void 0, e).toString(_enchex2.default),$=e=>{try{if(!e||e==="rgba(0, 0, 0, 0)"||e==="transparent")return;let{r:n,g:r,b:t,a:m}=_colord.colord.call(void 0, e).toRgb(),i=Math.round(m*255).toString(16).padStart(2,"0"),d=n.toString(16).padStart(2,"0"),y=r.toString(16).padStart(2,"0"),x=t.toString(16).padStart(2,"0");return`${i}${d}${y}${x}`.toUpperCase()}catch (e2){throw new Error(`Warna tidak valid ${e}`)}},V=e=>{if(e!=="none")switch(e){case"solid":return"thin";case"dashed":return"dashed";case"dotted":return"dotted";case"double":return"double";default:return}},K=(e="")=>{let n=e.match(/\.(\d+)/);return n?Math.pow(10,n[1].length):1},ne=(e="")=>(e||(e=""),typeof e=="string"?/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?(\?[&\w=.+-]*)?(#[\w-]*)?$/.test(e):!1),v=async e=>{if(!e)throw new Error("Value is required");let n=e;if(ne(e)){let d=await _axios2.default.get(e,{responseType:"arraybuffer"});n=Buffer.from(d.data,"binary").toString("base64")}let r=n.replace(/^data:image\/\w+;base64,/,""),t=Buffer.from(r,"base64"),m=new Uint8Array(t),i=_imagesize2.default.call(void 0, m);return{base64:n,extension:i.type||"png",width:i.width,height:i.height}},Y=(e,n,r="")=>{if(!e)return r;if(e.hasOwnProperty(n))return e[n];let t=n.replace(/\[(\d+)\]/g,".$1").split("."),m=e;for(let i of t){if(m==null)return r;m=m[i]}return m===void 0?r:m},U=e=>JSON.parse(JSON.stringify(e));function B(e){return typeof e=="number"?!Number.isNaN(e):typeof e=="string"&&e.trim()!==""?/^(\d+(\.\d+)?|\.\d+)$/.test(e.trim()):!1}var _moment = require('moment'); var _moment2 = _interopRequireDefault(_moment);var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);var _mathjs = require('mathjs'); var ce = _interopRequireWildcard(_mathjs); var I = _interopRequireWildcard(_mathjs);var _uuid = require('uuid');var M={};function ue(e){try{let n=_acorn2.default.parse(e,{ecmaVersion:2020,sourceType:"module"}),r=!1;return _acornwalk2.default.simple(n,{ReturnStatement(t){(!t.parent||t.parent.type!=="FunctionDeclaration")&&(r=!0)}}),r}catch (e3){return!1}}var W=async({json:e,html:n="",js:r,css:t})=>{try{let m=_handlebars2.default.create();r||(r=[""]),t||(t=[""]),typeof r=="string"&&(r=[r]),typeof t=="string"&&(t=[t]);let i=[],d="";r=r.filter(a=>a.trim()!=="");let y=r.join("");if(P(y)){let a=J(y);if(M[a])i=M[a].functions,d=M[a].functionComplext;else{for(let g=0;g<r.length;g++){let u=r[g];if(!ue(u))throw new Error('Invalid JavaScript code: "return" statement cannot be used outside of a function scope.');let c=_acorn2.default.parse(u,{ecmaVersion:2020,sourceType:"module"});_acornwalk2.default.simple(c,{FunctionDeclaration(l){let p=_optionalChain([l, 'access', _2 => _2.id, 'optionalAccess', _3 => _3.name]),s=u.slice(l.body.start,l.body.end);i.push({name:p,fn:new Function(...l.params.map(w=>w.name),s)})},VariableDeclaration(l){l.declarations.forEach(p=>{if(p.init.type==="FunctionExpression"||p.init.type==="ArrowFunctionExpression"){let s=p.id.name,w=u.slice(p.init.body.start,p.init.body.end);i.push({name:s,fn:new Function(...p.init.params.map(C=>C.name),w)})}})}}),d=` ${u}
`}M[a]={functions:i,functionComplext:d}}}d=` ${d}
({${i.map(a=>a.name).join(", ")}})`;let o=new (0, _vm2.VM)({timeout:1e3,sandbox:{moment:_moment2.default,axios:_axios2.default,lodash:_lodash2.default,mathjs:ce,uuid:{v4:_uuid.v4}}}).run(d);return i.forEach(a=>{m.registerHelper(a.name,o[a.name])}),Array.isArray(n)&&n?n.map(g=>m.compile(`${t.filter(c=>c).map(c=>`<style>${c}</style>
`)}${g}`)(e)):m.compile(`${t.filter(u=>u).map(u=>`<style>${u}</style>
`)}${n}`)(e)}catch(m){return m instanceof Error?new Error(`Error Compile: ${m.message}`):new Error("Error Compile: Unknown error")}};var _exceljs = require('exceljs'); var _exceljs2 = _interopRequireDefault(_exceljs);var N={sum:"sum",formula:"formula",iteration:"iteration",image:"image",asset:"asset",none:"none"};async function X(e,n,r="",t){let m=await W({html:e,json:n,js:r});return/^0|#,##0|0\.00|%/.test(t.numFmt)&&B(m)?Number(m):m}function de(e,n,r){try{let t=I.evaluate(n,e);return isNaN(t)?r:t}catch (e4){return r}}function ge(e,n,r){try{return e.reduce((m,i)=>{let d=I.evaluate(n,i);return m+(isNaN(d)?r:d)},0)}catch (e5){return r}}function he(e=""){let n=/\{\{\s*#each\s+(\S+)\s+((\(.*?\))|(\S+))\s*\}\}/,r=/\{\{\s*#each\s+(\S+)\s+formula\((.*?),\s*(\d+)\)\s*\}\}/,t=/\{\{\s*#sum\s+(\S+)\s+formula\((.*?)(,\s*(\d+))?\)\s*\}\}/,m=/\{\{\s*#image\s+(\S+)(?:\s+(\d+|auto)(?:,(\d+|auto))?)?\s*\}\}/,i=/\{\{\s*#asset\s+(\S+)(?:\s+(\d+|auto)(?:,(\d+|auto))?)?\s*\}\}/,d=typeof e=="string"?_optionalChain([e, 'optionalAccess', _4 => _4.match, 'call', _5 => _5(n)]):!1,y=typeof e=="string"?_optionalChain([e, 'optionalAccess', _6 => _6.match, 'call', _7 => _7(r)]):!1,x=typeof e=="string"?_optionalChain([e, 'optionalAccess', _8 => _8.match, 'call', _9 => _9(t)]):!1,o=typeof e=="string"?_optionalChain([e, 'optionalAccess', _10 => _10.match, 'call', _11 => _11(m)]):!1;return(typeof e=="string"?_optionalChain([e, 'optionalAccess', _12 => _12.match, 'call', _13 => _13(i)]):!1)?{type:N.asset,data:{field:o[1],width:o[2],height:o[3]}}:o?{type:N.image,data:{field:o[1],width:o[2],height:o[3]}}:x?{type:N.sum,data:{iteratorKey:x[1],expression:x[2],defaultValue:isNaN(x[4])?0:Number(x[4])}}:y?{type:N.formula,data:{iteratorKey:y[1],expression:y[2],defaultValue:isNaN(y[3])?0:Number(y[3])}}:d?{type:N.iteration,data:{iteratorKey:d[1],field:d[2]}}:{type:N.none,data:{}}}function ye(e,n,r){let t=e._merges;for(let m in t)if(t.hasOwnProperty(m)){let i=t[m].model;if(n>=i.top&&n<=i.bottom&&r>=i.left&&r<=i.right)return!0}return!1}var we=async({cell:e,json:n,js:r,worksheet:t,workbook:m,placeholders:i,rowNumber:d,colNumber:y})=>new Promise(async(x,o)=>{try{if(typeof e.value=="string"&&/{{.+}}/.test(e.value)){let{type:a,data:{field:g,iteratorKey:u,expression:k,defaultValue:c,width:l,height:p=l}}=he(e.value);if(a===N.sum){let s=Y(n,u);e.value=ge(s,k,c)}else if([N.image,N.asset].some(s=>s===a)){let s;if(a===N.image&&(s=Y(n,g)),s){let{base64:w,width:C,height:S,extension:f}=await v(s),R=m.addImage({base64:w,extension:f}),D=t.getColumn(e.col).width,E=t.getRow(e.row).height,T={width:l==="auto"?C:isNaN(l)?D*7:Number(l),height:p==="auto"?S:isNaN(p)?E*1.33:Number(p)};t.addImage(R,{tl:{col:e.col-1,row:e.row-1},...!l&&!p&&{br:{col:e.col,row:e.row}},editAs:"oneCell",ext:T}),e.value=""}}else if([N.formula,N.iteration].some(s=>s===a)){let s=Y(n,u);i.push({row:d,col:y,items:s,field:g,cell:e,type:a,expression:k,defaultValue:c}),e.value=""}else{let s=await X(e.value,n,r,e);e.value=s}}x(!0)}catch(a){a instanceof Error&&o(new Error(`Error Process File: ${a.message}`)),o(new Error("Error Process File: Unknown error"))}}),_=({buffer:e,json:n,js:r})=>new Promise(async(t,m)=>{try{let i=new _exceljs2.default.Workbook,d=[],y=await i.xlsx.load(e);for(let g of y.worksheets){let u=i.getWorksheet(g.name),k=[],c=[];_optionalChain([u, 'optionalAccess', _14 => _14.eachRow, 'call', _15 => _15(p=>c.push(p))]);for(let p of c){let s=[],w=p.number;p.eachCell(C=>s.push(C));for(let C of s)await we({cell:C,json:n,js:r,worksheet:u,workbook:i,placeholders:k,rowNumber:w,colNumber:C.col})}let l=k.reduce((p,s)=>(p[s.row]||(p[s.row]=[]),p[s.row].push(s),p),{});for(let p of Object.keys(l)){let s=parseInt(p),w=l[s],C=w[0].items;for(let[S,f]of C.entries()){S>0&&u.insertRow(s+S,0,[]);for(let{col:R,field:D,cell:E,type:T,defaultValue:A,expression:F}of w){let h=u.getCell(s+S,R);if(T===N.formula){let b=de(f,F,A);h.value=b}else{let b=await X(`{{${D}}}`,f,r,E);h.value=b}h.style=U(E.style),h.numFmt=E.numFmt}}}d.push({sheetName:g.name,placeholders:k,groupedPlaceholders:l})}let x=await i.xlsx.writeBuffer();(await i.xlsx.load(x)).eachSheet(g=>{let u=i.getWorksheet(g.name),{groupedPlaceholders:k}=d.find(c=>c.sheetName===g.name)||{};Object.keys(k).forEach(c=>{let l=parseInt(c),p=k[l];p[0].items.forEach((w,C)=>{C>0&&p.forEach(({col:S,cell:{_mergeCount:f}})=>{f&&f>1&&(ye(u,l+C,S)||u.mergeCells(l+C,S,l+C,S+f))})})})});let a=await i.xlsx.writeBuffer();t(a)}catch(i){i instanceof Error&&m(new Error(`Failed to template Excel files: ${i.message}`)),m(new Error("Failed to template Excel files: Unknown error"))}});var G=e=>new Promise(async(n,r)=>{try{let t=new _exceljs2.default.Workbook;for(let i of e){let d=new _exceljs2.default.Workbook;await d.xlsx.load(i),d.eachSheet(y=>{t.getWorksheet(y.name)&&t.removeWorksheet(y.name);let x=t.addWorksheet(y.name);y.columns.forEach((o,a)=>{let g=x.getColumn(a+1);o.width&&(g.width=o.width),o.style&&(g.style={...o.style})}),y.eachRow((o,a)=>{let g=x.getRow(a);o.height&&(g.height=o.height),o.eachCell({includeEmpty:!0},(u,k)=>{let c=g.getCell(k);c.value=u.value,u.style&&(c.style={...u.style}),u.formula&&(c.value={formula:u.formula,result:u.result})})}),y.model.merges&&y.model.merges.forEach(o=>{x.mergeCells(o)}),y.properties.tabColor&&(x.properties.tabColor={...y.properties.tabColor})})}let m=await t.xlsx.writeBuffer();n(m)}catch(t){t instanceof Error&&r(new Error(`Failed to merge Excel files: ${t.message}`)),r(new Error("Failed to merge Excel files: Unknown error"))}});var Q=(e,n)=>new Promise(async(r,t)=>{let m=await n.newPage();try{await m.setViewport({width:1e7,height:1080}),await m.setContent(`<style>* { font-family: Arial; font-size: 11px; }</style>
${e}`);let i=await m.evaluate(()=>Array.from(document.querySelectorAll("table")).map(a=>{let g=Array.from(a.querySelectorAll("tr"));return{sheetName:a.getAttribute("sheet-name")||a.getAttribute("name")||null,rows:g.map(u=>({cells:Array.from(u.querySelectorAll("td, th")).map(c=>{let l=getComputedStyle(c),p=c.getBoundingClientRect(),s=c.querySelector("img");return{text:Array.from(c.childNodes).map(w=>w.nodeName==="BR"?`
`:w.textContent).join("").trim(),colspan:parseInt(c.getAttribute("colspan"))||1,rowspan:parseInt(c.getAttribute("rowspan"))||1,image:s?{src:s.src,width:s.getBoundingClientRect().width,height:s.getBoundingClientRect().height,fullSize:s.getAttribute("full-size")==="true"}:null,styles:{fontFamily:l.fontFamily||"Arial",fontSize:parseInt(l.fontSize||"11"),fontWeight:l.fontWeight,fontStyle:l.fontStyle,textDecoration:l.textDecoration,color:l.color,backgroundColor:l.backgroundColor,textAlign:l.textAlign,verticalAlign:l.verticalAlign||"middle",wrapText:l.whiteSpace!=="nowrap",borders:{top:{style:l.borderTopStyle,color:l.borderTopColor},bottom:{style:l.borderBottomStyle,color:l.borderBottomColor},left:{style:l.borderLeftStyle,color:l.borderLeftColor},right:{style:l.borderRightStyle,color:l.borderRightColor}}},width:p.width,height:p.height,dataType:c.getAttribute("data-type")||c.getAttribute("type")||null,formatType:c.getAttribute("format-type")||c.getAttribute("format")||null,dateFormat:c.getAttribute("date-format")||null,decDigit:c.getAttribute("dec-digit")?parseInt(c.getAttribute("dec-digit")):c.getAttribute("dec-digits")?parseInt(c.getAttribute("dec-digits")):null}})}))}}));m.close().catch(()=>{});let d=new _exceljs2.default.Workbook,y=[];i.forEach((o,a)=>{let g=o.sheetName||`Sheet${a+1}`,u=d.addWorksheet(g),k=[],c=[],l={},p=[];o.rows.forEach((s,w)=>{let C=u.addRow([]),S=1;s.cells.forEach(f=>{for(;c[w]&&c[w][S];)S++;let R=f.colspan,D=f.rowspan;if((D>1||R>1)&&k.push({startRow:w+1,startCol:S,endRow:w+D,endCol:S+R-1}),D>1)for(let h=1;h<D;h++){c[w+h]||(c[w+h]={});for(let b=0;b<R;b++)c[w+h][S+b]=!0}let E=C.getCell(S),T=f.text;if(f.dataType==="formula")E.value={formula:T},f.formatType&&(E.numFmt=f.formatType);else if(f.dataType==="number"){let h=B(T)?Number(T):null;if(E.value=h,P(f.decDigit)&&typeof h=="number"){let b=Math.pow(10,f.decDigit);E.numFmt=`#,##0${f.decDigit>0?`.${"0".repeat(f.decDigit)}`:""}`,E.value=Math.floor(h*b)/b}if(f.formatType&&typeof h=="number"){E.numFmt=f.formatType;let b=K(f.formatType);E.value=Math.floor(h*b)/b}}else if(["date","dateTime","date-time","datetime"].some(h=>h===f.dataType)){let h=null;f.dateFormat?h=_moment2.default.utc(T,f.dateFormat):h=_moment2.default.utc(T,[_moment2.default.ISO_8601,"DD/MM/YYYY","MM/DD/YYYY","YYYY-MM-DD","YYYY/MM/DD","YYYY-MM-DD HH:mm:ss","YYYY/MM/DD HH:mm:ss","YYYY-MM-DDTHH:mm:ss.SSS[Z]"],!0),h.isValid()&&f.formatType?E.value=h.format(f.formatType):E.value=T}else f.dataType==="boolean"?E.value=T.toLowerCase()==="true":f.image?y.push({sheetIndex:a,src:f.image.src,width:f.image.width,height:f.image.height,row:w+1,column:S,colspan:f.colspan,rowspan:f.rowspan,fullSize:f.image.fullSize}):E.value=T;let A=f.styles;E.font={name:A.fontFamily||"Arial",size:A.fontSize||11,bold:parseInt(A.fontWeight)>=700,italic:A.fontStyle==="italic",underline:A.textDecoration.includes("underline"),strike:A.textDecoration.includes("line-through"),color:{argb:$(A.color)}},A.backgroundColor&&A.backgroundColor!=="rgba(0, 0, 0, 0)"&&(E.fill={type:"pattern",pattern:"solid",fgColor:{argb:$(A.backgroundColor)}}),E.alignment={horizontal:A.textAlign||"left",vertical:A.verticalAlign,wrapText:A.wrapText};let F={};if(["top","bottom","left","right"].forEach(h=>{let b=A.borders[h],O=V(b.style),z=$(b.color);O&&z&&(F[h]={style:O,color:{argb:z}})}),E.border=F,f.width){let h=f.width/R;for(let b=S;b<S+R;b++)(!l[b]||h>l[b])&&(l[b]=h)}if(f.height){let h=f.height/D;for(let b=w;b<w+D;b++)(!p[b]||h>p[b])&&(p[b]=h)}S+=R})}),Object.entries(l).forEach(([s,w])=>{let C=parseInt(s),S=w/5;u.getColumn(C).width=S}),p.forEach((s,w)=>{let C=u.getRow(w+1);C.height=s*.75}),k.forEach(s=>{u.mergeCells(s.startRow,s.startCol,s.endRow,s.endCol)})}),await Promise.all(y.map(async o=>{try{let{base64:a}=await v(o.src),g=d.worksheets[o.sheetIndex],u=d.addImage({base64:a,extension:"png"});g.addImage(u,{tl:{col:o.column-1,row:o.row-1},ext:{width:o.width,height:o.height},...o.fullSize&&{br:{col:o.column,row:o.row}},editAs:"oneCell"})}catch(a){console.error("Error processing image:",a)}}));let x=await d.xlsx.writeBuffer();r(x)}catch(i){m.close().catch(()=>{}),i instanceof Error&&t(new Error(`Error Compile: ${i.message}`)),t(new Error("Error Compile: Unknown error"))}});var Qe=async({json:e,html:n,js:r,css:t,fileName:m,browser:i,buffer:d})=>new Promise(async(y,x)=>{try{let o,a;if(/<table/i.test(n)){let u=await W({json:e,html:n,js:r,css:t});o=await Q(u,i)}if(d&&(a=await _({buffer:d,json:e,js:r})),!o&&!a)throw new Error("No data compiled");let g;o&&a?g=await G([a,o]):o?g=o:a&&(g=a),y({base64:g.toString("base64"),mimeType:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",extension:".xlsx",size:g.length,buffer:g,fileName:`${m||"Zeno Report"}`})}catch(o){o instanceof Error&&x(new Error(`${o.message}`)),x(new Error("Unknown error"))}});exports.excel = Qe;