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