UNPKG

xml-disassembler

Version:

Disassemble XML files into smaller, more manageable files and reassemble the XML when needed.

3 lines (2 loc) 12.3 kB
import{getLogger as e,configure as t}from"log4js";import{readFile as n,writeFile as r,rm as i,readdir as o,stat as s,mkdir as l,unlink as a}from"node:fs/promises";import{dirname as u,basename as d,join as c}from"node:path/posix";import{existsSync as f}from"node:fs";import{relative as m,resolve as y,dirname as h,join as p,basename as g,extname as b}from"node:path";import v from"ignore";import{XMLParser as P,XMLBuilder as E}from"fast-xml-parser";import{parse as N,stringify as j}from"json5";import{parse as x,stringify as A}from"smol-toml";import{parse as O,stringify as w}from"ini";import{parse as C,stringify as F}from"yaml";import{createHash as D}from"node:crypto";import{readFile as q}from"fs/promises";function $(e,t,n,r){return new(n||(n=Promise))(function(i,o){function s(e){try{a(r.next(e))}catch(e){o(e)}}function l(e){try{a(r.throw(e))}catch(e){o(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(s,l)}a((r=r.apply(e,t||[])).next())})}function _(e,t){for(const[n,r]of Object.entries(t))Array.isArray(r)?I(e,n,r):S(r)?k(e,n,r):G(e,n,r)}function I(e,t,n){e[t]?Array.isArray(e[t])?e[t].push(...n):e[t]=[e[t],...n]:e[t]=n}function k(e,t,n){Array.isArray(e[t])?e[t].push(n):e[t]?e[t]=[e[t],n]:e[t]=n}function G(e,t,n){Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n)}function S(e){return"object"==typeof e&&null!==e}"function"==typeof SuppressedError&&SuppressedError;const T={commentPropName:"!---",ignoreAttributes:!1,ignoreNameSpace:!1,parseTagValue:!1,parseNodeValue:!1,parseAttributeValue:!1,trimValues:!1,processEntities:!1,cdataPropName:"![CDATA["},W=Object.assign(Object.assign({},T),{format:!0,indentBy:" ",suppressBooleanAttributes:!1,suppressEmptyNode:!1});function B(e,t){return"#text"===e&&"string"==typeof t&&""===t.trim()}function X(e){return Array.isArray(e)?e.map(X).filter(e=>!("object"==typeof e&&0===Object.keys(e).length)):"object"==typeof e&&null!==e?function(e){const t={};for(const n in e){const r=e[n];if(B(n,r))continue;const i=X(r);void 0!==i&&(t[n]=i)}return t}(e):e}let M=null;function V(e){return $(this,void 0,void 0,function*(){const t=(M||(M=new P(T)),M);let r;try{const i=yield n(e,"utf-8");r=t.parse(i,!0);return X(r)}catch(t){return void ce.error(`${e} was unabled to be parsed and will not be processed. Confirm formatting and try again.`)}})}const J={".yaml":C,".yml":C,".json":JSON.parse,".json5":N,".toml":x,".ini":O};function K(e){return $(this,void 0,void 0,function*(){if(e.endsWith(".xml"))return yield V(e);const t=Object.keys(J).find(t=>e.endsWith(t)),n=yield q(e,"utf-8");return J[t](n)})}class L{reassemble(e){return $(this,void 0,void 0,function*(){const{filePath:t,fileExtension:n,postPurge:o=!1}=e;if(!(yield this._validateDirectory(t)))return;ce.debug(`Parsing directory to reassemble: ${t}`);const s=yield this.processFilesInDirectory(t);if(!s.length)return void this._logEmptyParseError(t);const l=R(function(e){if(0===e.length)return void ce.error("No elements to merge.");const t=e[0],n=Object.keys(t).find(e=>"?xml"!==e),r={};for(const t of e)_(r,t[n]);return function(e,t,n){return e?{"?xml":e,[t]:n}:{[t]:n}}(t["?xml"],n,r)}(s)),a=this._getOutputPath(t,n);yield r(a,l,"utf-8"),o&&(yield i(t,{recursive:!0}))})}processFilesInDirectory(e){return $(this,void 0,void 0,function*(){const t=[],n=yield o(e),r=this._sortFilesByBaseName(n).map(t=>s(c(e,t)).then(e=>({file:t,stats:e}))),i=yield Promise.all(r);for(const{file:n,stats:r}of i){const i=c(e,n);if(r.isFile()&&this._isParsableFile(n)){const e=yield K(i);e&&t.push(e)}else if(r.isDirectory()){const e=yield this.processFilesInDirectory(i);t.push(...e)}}return t})}_sortFilesByBaseName(e){return e.sort((e,t)=>e.split(".")[0].localeCompare(t.split(".")[0]))}_isParsableFile(e){return/\.(xml|json|json5|ya?ml|toml|ini)$/i.test(e)}_validateDirectory(e){return $(this,void 0,void 0,function*(){return!!(yield s(e)).isDirectory()||(ce.error(`The provided path to reassemble is not a directory: ${e}`),!1)})}_logEmptyParseError(e){ce.error(`No files under ${e} were parsed successfully. A reassembled XML file was not created.`)}_getOutputPath(e,t){const n=u(e),r=d(e);return c(n,`${r}.${null!=t?t:"xml"}`)}}let Q=null;function R(e){return(Q||(Q=new E(W)),Q).build(e).trimEnd()}function U(e){return $(this,void 0,void 0,function*(){return F(e)})}function z(e){return $(this,void 0,void 0,function*(){return j(e,null,2)})}function H(e){return $(this,void 0,void 0,function*(){return JSON.stringify(e,null,2)})}function Y(e){return $(this,void 0,void 0,function*(){return A(e)})}function Z(e){return $(this,void 0,void 0,function*(){return w(e)})}const ee={yaml:U,json5:z,json:H,toml:Y,ini:Z};const te=new WeakMap;function ne(e,t){var n,r;if(!t)return ie(e);return null!==(r=null!==(n=function(e,t){for(const n of t){const t=e[n];if("string"==typeof t)return t}}(e,t.split(",")))&&void 0!==n?n:function(e,t){for(const n in e){const r=e[n];if(!re(r))continue;const i=ne(r,t);if(i)return i}}(e,t))&&void 0!==r?r:ie(e)}function re(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function ie(e){let t=te.get(e);t||(t=JSON.stringify(e),te.set(e,t));return D("sha256").update(t).digest("hex").slice(0,8)}function oe(e){return $(this,arguments,void 0,function*({content:e,disassembledPath:t,outputFileName:n,subdirectory:i,wrapKey:o,isGroupedArray:s=!1,rootElementName:a,rootAttributes:u,xmlDeclaration:d,format:f,uniqueIdElements:m}){const y=i?c(t,i):t;let h=n;if(!h&&o&&!s&&"object"==typeof e){h=`${ne(e,m)}.${o}-meta.${f}`}const p=c(y,h);yield l(y,{recursive:!0});let g={[a]:Object.assign(Object.assign({},u),o?{[o]:e}:e)};"object"==typeof d&&null!==d&&(g=Object.assign({"?xml":d},g));const b=function(e){return ee[e]}(f),v=b?yield b(g):R(g);yield r(p,v),ce.debug(`Created disassembled file: ${p}`)})}function se(e){return $(this,void 0,void 0,function*(){const{element:t,disassembledPath:n,uniqueIdElements:r,rootElementName:i,rootAttributes:o,key:s,leafCount:l,hasNestedElements:a,format:u,xmlDeclaration:d,strategy:c}=e,f=Array.isArray(t),m="object"==typeof t&&null!==t&&Object.keys(t).some(e=>!e.startsWith("#"));return f||m?"grouped-by-tag"===c?{leafContent:{},leafCount:l,hasNestedElements:!0,nestedGroups:{[s]:[t]}}:(yield oe({content:t,disassembledPath:n,subdirectory:s,wrapKey:s,rootElementName:i,rootAttributes:o,xmlDeclaration:d,format:u,uniqueIdElements:r}),{leafContent:{},leafCount:l,hasNestedElements:!0}):{leafContent:{[s]:[t]},leafCount:l+1,hasNestedElements:a}})}function le(e){return $(this,arguments,void 0,function*({filePath:e,disassembledPath:t,baseName:n,postPurge:r,format:i,uniqueIdElements:o,strategy:s}){const l=yield V(e);if(!l)return;const{rootElementName:u,rootElement:d,xmlDeclaration:c}=function(e){const t=e["?xml"],n="object"==typeof t&&null!==t?t:void 0,r=Object.keys(e).find(e=>"?xml"!==e),i=e[r];return{rootElementName:r,rootElement:i,xmlDeclaration:n}}(l),f=function(e){const t={};for(const[n,r]of Object.entries(e))n.startsWith("@")&&"string"==typeof r&&(t[n]=r);return t}(d),m=Object.keys(d).filter(e=>!e.startsWith("@")),{leafContent:y,nestedGroups:h,leafCount:p,hasNestedElements:g}=yield function(e){return $(this,arguments,void 0,function*({rootElement:e,keyOrder:t,disassembledPath:n,rootElementName:r,rootAttributes:i,xmlDeclaration:o,uniqueIdElements:s,strategy:l,format:a}){var u,d;let c={},f={},m=0,y=!1;const h=20;for(const p of t){const t=Array.isArray(e[p])?e[p]:[e[p]];for(let e=0;e<t.length;e+=h){const g=t.slice(e,e+h),b=yield Promise.all(g.map((e,t)=>se({element:e,disassembledPath:n,uniqueIdElements:s,rootElementName:r,rootAttributes:i,key:p,leafCount:m,hasNestedElements:y,format:a,xmlDeclaration:o,strategy:l})));for(let e=0;e<b.length;e++){const t=b[e];if(t.leafContent[p]&&(c[p]=[...null!==(u=c[p])&&void 0!==u?u:[],...t.leafContent[p]]),"grouped-by-tag"===l&&t.nestedGroups)for(const e in t.nestedGroups)f[e]=[...null!==(d=f[e])&&void 0!==d?d:[],...t.nestedGroups[e]];m=t.leafCount,y=t.hasNestedElements}}}return{leafContent:c,nestedGroups:f,leafCount:m,hasNestedElements:y}})}({rootElement:d,keyOrder:m,disassembledPath:t,rootElementName:u,rootAttributes:f,xmlDeclaration:c,uniqueIdElements:o,strategy:s,format:i});(function(e,t,n){if(!t&&e>0)return ce.error(`The XML file ${n} only has leaf elements. This file will not be disassembled.`),!0;return!1})(p,g,e)||(yield function(e,t,n){return $(this,void 0,void 0,function*(){if("grouped-by-tag"===t)for(const t in e)yield oe({content:e[t],disassembledPath:n.disassembledPath,outputFileName:`${t}.${n.format}`,wrapKey:t,isGroupedArray:!0,rootElementName:n.rootElementName,rootAttributes:n.rootAttributes,xmlDeclaration:n.xmlDeclaration,format:n.format})})}(h,s,{disassembledPath:t,rootElementName:u,rootAttributes:f,xmlDeclaration:c,format:i}),yield function(e){return $(this,arguments,void 0,function*({leafCount:e,leafContent:t,strategy:n,keyOrder:r,options:i}){if(0===e)return;const o="grouped-by-tag"===n?function(e,t){const n={};for(const r of t)void 0!==e[r]&&(n[r]=e[r]);return n}(t,r):t;yield oe(Object.assign({content:o},i))})}({leafCount:p,leafContent:y,strategy:s,keyOrder:m,options:{disassembledPath:t,outputFileName:`${n}.${i}`,rootElementName:u,rootAttributes:f,xmlDeclaration:c,format:i}}),r&&(yield a(e)))})}class ae{constructor(e=10){this.queue=[],this.running=0,this.concurrency=e}add(e){return $(this,void 0,void 0,function*(){return new Promise((t,n)=>{this.queue.push(()=>$(this,void 0,void 0,function*(){try{const n=yield e();t(n)}catch(e){n(e)}})),this.process()})})}process(){return $(this,void 0,void 0,function*(){if(this.running>=this.concurrency||0===this.queue.length)return;this.running++;const e=this.queue.shift();try{yield e()}finally{this.running--,this.process()}})}waitForCompletion(){return $(this,void 0,void 0,function*(){for(;this.running>0||this.queue.length>0;)yield new Promise(e=>setTimeout(e,10))})}}class ue{constructor(){this.ign=v(),this.taskQueue=new ae(10)}disassemble(e){return $(this,void 0,void 0,function*(){let{filePath:t,uniqueIdElements:n,strategy:r="unique-id",prePurge:i=!1,postPurge:o=!1,ignorePath:l=".xmldisassemblerignore",format:a="xml"}=e;["unique-id","grouped-by-tag"].includes(r)||(ce.warn(`Unsupported strategy "${r}", defaulting to "unique-id".`),r="unique-id"),yield this._loadIgnoreRules(l);const u=yield s(t),d=this.posixPath(m(process.cwd(),t));u.isFile()?yield this._handleFile(t,d,{uniqueIdElements:n,strategy:r,prePurge:i,postPurge:o,format:a}):u.isDirectory()&&(yield this._handleDirectory(t,{uniqueIdElements:n,strategy:r,prePurge:i,postPurge:o,format:a,ignorePath:l}))})}_loadIgnoreRules(e){return $(this,void 0,void 0,function*(){const t=y(e);if(f(t)){const e=yield n(t);this.ign.add(e.toString())}})}_handleFile(e,t,n){return $(this,void 0,void 0,function*(){const r=y(e);if(!this._isXmlFile(r))return void ce.error(`The file path provided is not an XML file: ${r}`);if(this.ign.ignores(t))return void ce.warn(`File ignored by ignore rules: ${r}`);const i=h(r);yield this.processFile(Object.assign(Object.assign({},n),{dirPath:i,filePath:r}))})}_handleDirectory(e,t){return $(this,void 0,void 0,function*(){const n=(yield o(e)).map(n=>$(this,void 0,void 0,function*(){const r=p(e,n),i=this.posixPath(m(process.cwd(),r));if(this._isXmlFile(r)&&!this.ign.ignores(i))return this.taskQueue.add(()=>this.processFile(Object.assign(Object.assign({},t),{dirPath:e,filePath:r})));this.ign.ignores(i)&&ce.warn(`File ignored by ignore rules: ${r}`)}));yield Promise.all(n)})}_isXmlFile(e){return e.endsWith(".xml")}processFile(e){return $(this,void 0,void 0,function*(){const{dirPath:t,strategy:n,filePath:r,uniqueIdElements:o,prePurge:s,postPurge:l,format:a}=e;ce.debug(`Parsing file to disassemble: ${r}`);const u=g(r,b(r)),d=u.split(".")[0],c=p(t,d);s&&f(c)&&(yield i(c,{recursive:!0})),yield le({filePath:r,disassembledPath:c,uniqueIdElements:o,baseName:u,postPurge:l,format:a,strategy:n})})}posixPath(e){return e.replace(/\\+/g,"/")}}function de(t){e().level=t}const ce=e();t({appenders:{disassemble:{type:"file",filename:"disassemble.log"}},categories:{default:{appenders:["disassemble"],level:"error"}}});export{ue as DisassembleXMLFileHandler,L as ReassembleXMLFileHandler,R as buildXMLString,ce as logger,V as parseXML,de as setLogLevel,Z as transformToIni,H as transformToJson,z as transformToJson5,Y as transformToToml,U as transformToYaml}; //# sourceMappingURL=index.min.mjs.map