xml-disassembler
Version:
Disassemble XML files into smaller, more manageable files and reassemble the XML when needed.
3 lines (2 loc) • 10.8 kB
JavaScript
import{getLogger as e,configure as t}from"log4js";import{writeFile as n,readFile as i,readdir as s,stat as o,rm as r,mkdir as l,unlink as d}from"node:fs/promises";import{join as a,dirname as c,basename as u}from"node:path/posix";import{parse as f,stringify as m}from"yaml";import{parse as p,stringify as y}from"json5";import{parse as h,stringify as $}from"smol-toml";import{parse as g,stringify as b}from"ini";import{existsSync as v}from"node:fs";import{resolve as x,relative as j,dirname as E,join as P,basename as C,extname as w}from"node:path";import N from"ignore";import{createHash as O}from"node:crypto";import{XMLBuilder as A,XMLParser as S}from"fast-xml-parser";function W(e,t,n,i){return new(n||(n=Promise))((function(s,o){function r(e){try{d(i.next(e))}catch(e){o(e)}}function l(e){try{d(i.throw(e))}catch(e){o(e)}}function d(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,l)}d((i=i.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const T=" ",D={commentPropName:"!---",ignoreAttributes:!1,ignoreNameSpace:!1,parseTagValue:!1,parseNodeValue:!1,parseAttributeValue:!1,trimValues:!0,processEntities:!1,cdataPropName:"![CDATA["},F=Object.assign(Object.assign({},D),{format:!0,indentBy:T,suppressBooleanAttributes:!1,suppressEmptyNode:!1});function k(e,t=0){return new A(F).build(e).split("\n").map((e=>`${" ".repeat(4*t)}${e}`)).join("\n").trimEnd()}function I(e){return W(this,void 0,void 0,(function*(){const t=new S(D),n=yield i(e,"utf-8");let s;try{return s=t.parse(n,!0),s}catch(t){return void ie.error(`${e} was unabled to be parsed and will not be processed. Confirm formatting and try again.`)}}))}function q(e,t){let n=`<${t}`;for(const[t,i]of Object.entries(e))if(t.startsWith("@")){n+=` ${t.slice(2)}="${String(i)}"`}return n+=">",n}function L(e){let t='<?xml version="1.0" encoding="UTF-8"?>';if(e["?xml"]){const n=e["?xml"];t=`<?xml ${Object.entries(n).map((([e,t])=>`${e.replace("@_","")}="${t}"`)).join(" ")}?>`}return t}function X(e){return W(this,void 0,void 0,(function*(){const t=L(e),n=Object.keys(e)[1];return[n,q(e[n],n),t]}))}class G{processFilesInDirectory(e){return W(this,void 0,void 0,(function*(){const t=[];let n;const i=yield s(e);i.sort(((e,t)=>{const n=e.split(".")[0].toLowerCase(),i=t.split(".")[0].toLowerCase();return n.localeCompare(i)}));for(const s of i){const i=a(e,s),r=yield o(i);if(r.isFile()){if(/\.(xml|json|json5|ya?ml|toml|ini)$/.test(s)){const e=yield this.parseToXmlObject(i);if(void 0===e)continue;n=yield X(e);const s=k(e);t.push(s)}}else if(r.isDirectory()){const[e,s]=yield this.processFilesInDirectory(i);t.push(...e),n=s}}return[t,n]}))}reassemble(e){return W(this,void 0,void 0,(function*(){const{filePath:t,fileExtension:i,postPurge:s=!1}=e;let l=[];if(!(yield o(t)).isDirectory())return void ie.error(`The provided path to reassemble is not a directory: ${t}`);ie.debug(`Parsing directory to reassemble: ${t}`);const[d,f]=yield this.processFilesInDirectory(t);l=d;const m=c(t),p=u(t),y=a(m,i?`${p}.${i}`:`${p}.xml`);if(void 0!==f){const[e,i,o]=f;yield function(e,t,i,s,o){return W(this,void 0,void 0,(function*(){let r=e.join("\n");const l=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),d=new RegExp(`^\\s*${l}\\s*$`,"gm");r=r.replace(d,""),r=r.replace(new RegExp(`<${i}\\s*[^>]*>`,"g"),""),r=r.replace(new RegExp(`</${i}>`,"g"),""),r=r.replace(/<!\[CDATA\[\s*([\s\S]*?)\s*]]>/g,(function(e,t){const n=t.trim().split("\n").map((function(e){return e.replace(/^\s*/,"")}));return"<![CDATA[\n"+T+n.join("\n"+T)+"\n]]>"})),r=r.replace(/(\n\s*){2,}/g,`\n${T}`);const a=`</${i}>`;yield n(t,`${o}\n${s}${r}${a}`),ie.debug(`Created reassembled file: ${t}`)}))}(l,y,e,i,o),s&&(yield r(t,{recursive:!0}))}else ie.error(`No files under ${t} were parsed successfully. A reassembled XML file was not created.`)}))}parseToXmlObject(e){return W(this,void 0,void 0,(function*(){if(e.endsWith(".xml"))return yield I(e);const t=yield i(e,"utf-8");let n;return e.endsWith(".yaml")||e.endsWith(".yml")?n=f(t):e.endsWith(".json5")?n=p(t):e.endsWith(".json")?n=JSON.parse(t):e.endsWith(".toml")?n=h(t):e.endsWith(".ini")&&(n=g(t)),n}))}}function M(e,t){if(void 0===t)return V(e);const n=t.split(",");for(const t of n)if(void 0!==e[t]&&"string"==typeof e[t])return e[t];for(const n in e)if("object"==typeof e[n]&&null!==e[n]){const i=M(e[n],t);if(void 0!==i)return i}return V(e)}function V(e){const t=O("sha256");t.update(JSON.stringify(e));return t.digest("hex").slice(0,8)}function _(e){return W(this,void 0,void 0,(function*(){const t=yield I(e),i=m(t),s=e.replace(/\.xml$/,".yaml");yield n(s,i),ie.debug(`${e} has been transformed into ${s}`)}))}function H(e){return W(this,void 0,void 0,(function*(){const t=yield I(e),i=y(t,null,2),s=e.replace(/\.xml$/,".json5");yield n(s,i),ie.debug(`${e} has been transformed into ${s}`)}))}function J(e){return W(this,void 0,void 0,(function*(){const t=yield I(e),i=JSON.stringify(t,null,2),s=e.replace(/\.xml$/,".json");yield n(s,i),ie.debug(`${e} has been transformed into ${s}`)}))}function R(e){return W(this,void 0,void 0,(function*(){const t=yield I(e),i=$(t),s=e.replace(/\.xml$/,".toml");yield n(s,i),ie.debug(`${e} has been transformed into ${s}`)}))}function B(e){return W(this,void 0,void 0,(function*(){const t=yield I(e),i=b(t),s=e.replace(/\.xml$/,".ini");yield n(s,i),ie.debug(`${e} has been transformed into ${s}`)}))}function U(e){switch(e){case"yaml":return _;case"json5":return H;case"json":return J;case"toml":return R;case"ini":return B;default:return}}function z(e,t,i,s,o,d,c,u,f){return W(this,void 0,void 0,(function*(){let m="";const p=M(e,i),y=a(t,d),h=a(y,`${p}.${d}-meta.xml`);yield l(y,{recursive:!0});const $=q(e,d);m=k(e,2);let g=`${u}\n`;g+=`${o}\n`,g+=`${c}${$}\n`,g+=`${m}\n`,g+=`${c}</${d}>\n`,g+=`</${s}>`,yield n(h,g),ie.debug(`Created disassembled file: ${h}`);const b=U(f);b&&(yield b(h),yield r(h))}))}function K(e){return W(this,void 0,void 0,(function*(){const{element:t,disassembledPath:n,uniqueIdElements:i,rootElementName:s,rootElementHeader:o,key:r,indent:l,leafContent:d,leafCount:a,hasNestedElements:c,xmlDeclarationStr:u,format:f}=e;if("object"==typeof t)return yield z(t,n,i,s,o,r,l,u,f),[d,a,!0];return[`${d}${l}<${r}>${String(t)}</${r}>\n`,a+1,c]}))}function Q(e,t,i,s,o,l,d){return W(this,void 0,void 0,(function*(){let c=`${l}\n`;c+=`${o}\n`,c+=e,c+=`</${s}>`;const u=a(t,`${i}.xml`);yield n(u,c),ie.debug(`Created disassembled file: ${u}`);const f=U(d);f&&(yield f(u),yield r(u))}))}function Y(e){return W(this,void 0,void 0,(function*(){const{element:t,key:n,indent:i,leafContent:s,leafCount:o,hasNestedElements:r}=e,l={};if("object"==typeof t)return l[n]||(l[n]=[]),l[n].push(t),{leafContent:s,leafCount:o,hasNestedElements:!0,nestedGroups:l};return{leafContent:`${s}${i}<${n}>${String(t)}</${n}>\n`,leafCount:o+1,hasNestedElements:r,nestedGroups:l}}))}function Z(e,t,i,s,o,d,c,u){return W(this,void 0,void 0,(function*(){const f=a(i,`${e}.xml`);yield l(i,{recursive:!0});let m=`${d}\n${o}\n`;for(const n of t){const t=Object.entries(n).filter((([e,t])=>ee(e,t))).map((([e,t])=>` ${e.replace(/^@_/,"")}="${t}"`)).join(""),i=Object.fromEntries(Object.entries(n).filter((([e])=>!e.startsWith("@_"))));m+=`${c}<${e}${t}>\n`,m+=k(i,2),m+=`\n${c}</${e}>\n`}m+=`</${s}>`,yield n(f,m),ie.debug(`Created grouped nested file: ${f}`);const p=U(u);p&&(yield p(f),yield r(f))}))}function ee(e,t){return e.startsWith("@_")&&("string"==typeof t||"number"==typeof t)}class te{constructor(){this.ign=N()}disassemble(e){return W(this,void 0,void 0,(function*(){const{filePath:t,uniqueIdElements:n,strategy:r="unique-id",prePurge:l=!1,postPurge:d=!1,ignorePath:a=".xmldisassemblerignore",format:c="xml"}=e,u=x(a);if(v(u)){const e=yield i(u);this.ign.add(e.toString())}const f=yield o(t),m=this.posixPath(j(process.cwd(),t));if(f.isFile()){const e=x(t);if(!e.endsWith(".xml"))return void ie.error(`The file path provided is not an XML file: ${e}`);if(this.ign.ignores(m))return void ie.warn(`File ignored by ${a}: ${e}`);const i=E(e);yield this.processFile({dirPath:i,strategy:r,filePath:e,uniqueIdElements:n,prePurge:l,postPurge:d,format:c})}else if(f.isDirectory()){const e=yield s(t);for(const i of e){const e=P(t,i),s=this.posixPath(j(process.cwd(),e));e.endsWith(".xml")&&!this.ign.ignores(s)?yield this.processFile({dirPath:t,strategy:r,filePath:e,uniqueIdElements:n,prePurge:l,postPurge:d,format:c}):this.ign.ignores(s)&&ie.warn(`File ignored by ${a}: ${e}`)}}}))}processFile(e){return W(this,void 0,void 0,(function*(){const{dirPath:t,strategy:n,filePath:i,uniqueIdElements:s,prePurge:o,postPurge:l,format:a}=e;ie.debug(`Parsing file to disassemble: ${i}`);const c=C(i,w(i)),u=c.split(".")[0];let f;f=P(t,u),o&&v(f)&&(yield r(f,{recursive:!0})),"grouped-by-tag"===n?yield function(e,t,n,i,s,o){return W(this,void 0,void 0,(function*(){const r=yield I(e);if(void 0===r)return;const l=Object.keys(r)[1],a=L(r),c=r[l],u=q(c,l);let f="",m=0,p=!1;const y={};for(const e of Object.keys(c).filter((e=>!e.startsWith("@")))){const t=Array.isArray(c[e])?c[e]:[c[e]];for(const n of t){const t=yield Y({element:n,key:e,indent:i,leafContent:f,leafCount:m,hasNestedElements:p});f=t.leafContent,m=t.leafCount,p=t.hasNestedElements;for(const e in t.nestedGroups)y[e]||(y[e]=[]),y[e].push(...t.nestedGroups[e])}}if(p){for(const e in y)yield Z(e,y[e],t,l,u,a,i,o);m>0&&(yield Q(f,t,n,l,u,a,o)),s&&(yield d(e))}else ie.error(`The XML file ${e} only has leaf elements. This file will not be disassembled.`)}))}(i,f,c,T,l,a):yield function(e,t,n,i,s,o,r){return W(this,void 0,void 0,(function*(){const l=yield I(e);if(void 0===l)return;const a=Object.keys(l)[1],c=L(l),u=l[a],f=q(u,a);let m="",p=0,y=!1;for(const e of Object.keys(u).filter((e=>!e.startsWith("@"))))if(Array.isArray(u[e]))for(const i of u[e]){const[o,l,d]=yield K({element:i,disassembledPath:t,uniqueIdElements:n,rootElementName:a,rootElementHeader:f,key:e,indent:s,leafContent:m,leafCount:p,hasNestedElements:y,xmlDeclarationStr:c,format:r});m=o,p=l,y=d}else{const[i,o,l]=yield K({element:u[e],disassembledPath:t,uniqueIdElements:n,rootElementName:a,rootElementHeader:f,key:e,indent:s,leafContent:m,leafCount:p,hasNestedElements:y,xmlDeclarationStr:c,format:r});m=i,p=o,y=l}y?(p>0&&(yield Q(m,t,i,a,f,c,r)),o&&d(e)):ie.error(`The XML file ${e} only has leaf elements. This file will not be disassembled.`)}))}(i,f,s,c,T,l,a)}))}posixPath(e){return e.replace(/\\+/g,"/")}}function ne(t){e().level=t}const ie=e();t({appenders:{disassemble:{type:"file",filename:"disassemble.log"}},categories:{default:{appenders:["disassemble"],level:"error"}}});export{te as DisassembleXMLFileHandler,G as ReassembleXMLFileHandler,k as buildXMLString,ie as logger,I as parseXML,ne as setLogLevel};
//# sourceMappingURL=index.min.mjs.map