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