1{"version":3,"file":"XML.js","names":["writeXMLAsync","options","xml","format","fs","promises","mkdir","path","dirname","recursive","writeFile","readXMLAsync","contents","readFile","encoding","flag","parser","Parser","manifest","parseStringPromise","fallback","Array","isArray","resources","string","$","translatable","_","unescapeAndroidString","parseXMLAsync","stringTimesN","n","char","join","indentLevel","newline","EOL","xmlInput","toString","builder","Builder","headless","escapeAndroidString","buildObject","Error","indentString","formatted","regex","replace","pad","split","map","line","trim","forEach","indent","match","padding","value","m"],"sources":["../../src/utils/XML.ts"],"sourcesContent":["import fs from 'fs';\nimport { EOL } from 'os';\nimport path from 'path';\nimport { Builder, Parser } from 'xml2js';\n\nexport type XMLValue = boolean | number | string | null | XMLArray | XMLObject;\n\nexport interface XMLArray extends Array<XMLValue> {}\n\nexport interface XMLObject {\n [key: string]: XMLValue | undefined;\n}\n\nexport async function writeXMLAsync(options: { path: string; xml: any }): Promise<void> {\n const xml = format(options.xml);\n await fs.promises.mkdir(path.dirname(options.path), { recursive: true });\n await fs.promises.writeFile(options.path, xml);\n}\n\nexport async function readXMLAsync(options: {\n path: string;\n fallback?: string | null;\n}): Promise<XMLObject> {\n let contents: string = '';\n try {\n contents = await fs.promises.readFile(options.path, { encoding: 'utf8', flag: 'r' });\n } catch {\n // catch and use fallback\n }\n const parser = new Parser();\n const manifest = await parser.parseStringPromise(contents || options.fallback || '');\n\n // For strings.xml\n if (Array.isArray(manifest?.resources?.string)) {\n for (const string of manifest?.resources?.string) {\n if (string.$.translatable === 'false' || string.$.translatable === false) {\n continue;\n }\n string._ = unescapeAndroidString(string._);\n }\n }\n\n return manifest;\n}\n\nexport async function parseXMLAsync(contents: string): Promise<XMLObject> {\n const xml = await new Parser().parseStringPromise(contents);\n return xml;\n}\n\nconst stringTimesN = (n: number, char: string) => Array(n + 1).join(char);\n\nexport function format(manifest: any, { indentLevel = 2, newline = EOL } = {}): string {\n let xmlInput: string;\n if (typeof manifest === 'string') {\n xmlInput = manifest;\n } else if (manifest.toString) {\n const builder = new Builder({\n headless: true,\n });\n\n // For strings.xml\n if (Array.isArray(manifest?.resources?.string)) {\n for (const string of manifest?.resources?.string) {\n if (string.$.translatable === 'false' || string.$.translatable === false) {\n continue;\n }\n string._ = escapeAndroidString(string._);\n }\n }\n\n xmlInput = builder.buildObject(manifest);\n\n return xmlInput;\n } else {\n throw new Error(`Invalid XML value passed in: ${manifest}`);\n }\n const indentString = stringTimesN(indentLevel, ' ');\n\n let formatted = '';\n const regex = /(>)(<)(\\/*)/g;\n const xml = xmlInput.replace(regex, `$1${newline}$2$3`);\n let pad = 0;\n xml\n .split(/\\r?\\n/)\n .map((line: string) => line.trim())\n .forEach((line: string) => {\n let indent = 0;\n if (line.match(/.+<\\/\\w[^>]*>$/)) {\n indent = 0;\n } else if (line.match(/^<\\/\\w/)) {\n if (pad !== 0) {\n pad -= 1;\n }\n } else if (line.match(/^<\\w([^>]*[^/])?>.*$/)) {\n indent = 1;\n } else {\n indent = 0;\n }\n\n const padding = stringTimesN(pad, indentString);\n formatted += padding + line + newline;\n pad += indent;\n });\n\n return formatted.trim();\n}\n\n/**\n * Escapes Android string literals, specifically characters `\"`, `'`, `\\`, `\\n`, `\\r`, `\\t`\n *\n * @param value unescaped Android XML string literal.\n */\nexport function escapeAndroidString(value: string): string {\n value = value.replace(/[\\n\\r\\t'\"@]/g, (m) => {\n switch (m) {\n case '\"':\n case \"'\":\n case '@':\n return '\\\\' + m;\n case '\\n':\n return '\\\\n';\n case '\\r':\n return '\\\\r';\n case '\\t':\n return '\\\\t';\n default:\n throw new Error(`Cannot escape unhandled XML character: ${m}`);\n }\n });\n if (value.match(/(^\\s|\\s$)/)) {\n value = '\"' + value + '\"';\n }\n return value;\n}\n\nexport function unescapeAndroidString(value: string): string {\n return value.replace(/\\\\(.)/g, '$1');\n}\n"],"mappings":"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"}