1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports._processAndroidXML = _processAndroidXML; 7exports.escapeAndroidString = escapeAndroidString; 8exports.format = format; 9exports.parseXMLAsync = parseXMLAsync; 10exports.readXMLAsync = readXMLAsync; 11exports.unescapeAndroidString = unescapeAndroidString; 12exports.writeXMLAsync = writeXMLAsync; 13function _fs() { 14 const data = _interopRequireDefault(require("fs")); 15 _fs = function () { 16 return data; 17 }; 18 return data; 19} 20function _os() { 21 const data = require("os"); 22 _os = function () { 23 return data; 24 }; 25 return data; 26} 27function _path() { 28 const data = _interopRequireDefault(require("path")); 29 _path = function () { 30 return data; 31 }; 32 return data; 33} 34function _xml2js() { 35 const data = require("xml2js"); 36 _xml2js = function () { 37 return data; 38 }; 39 return data; 40} 41function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 42async function writeXMLAsync(options) { 43 const xml = format(options.xml); 44 await _fs().default.promises.mkdir(_path().default.dirname(options.path), { 45 recursive: true 46 }); 47 await _fs().default.promises.writeFile(options.path, xml); 48} 49async function readXMLAsync(options) { 50 let contents = ''; 51 try { 52 contents = await _fs().default.promises.readFile(options.path, { 53 encoding: 'utf8', 54 flag: 'r' 55 }); 56 } catch { 57 // catch and use fallback 58 } 59 const parser = new (_xml2js().Parser)(); 60 const manifest = await parser.parseStringPromise(contents || options.fallback || ''); 61 return _processAndroidXML(manifest); 62} 63function _processAndroidXML(manifest) { 64 var _manifest$resources; 65 // For strings.xml 66 if (Array.isArray(manifest === null || manifest === void 0 ? void 0 : (_manifest$resources = manifest.resources) === null || _manifest$resources === void 0 ? void 0 : _manifest$resources.string)) { 67 for (const string of manifest === null || manifest === void 0 ? void 0 : (_manifest$resources2 = manifest.resources) === null || _manifest$resources2 === void 0 ? void 0 : _manifest$resources2.string) { 68 var _manifest$resources2; 69 if (string.$.translatable === 'false' || string.$.translatable === false) { 70 continue; 71 } 72 string._ = unescapeAndroidString(string._); 73 } 74 } 75 return manifest; 76} 77async function parseXMLAsync(contents) { 78 const xml = await new (_xml2js().Parser)().parseStringPromise(contents); 79 return xml; 80} 81const stringTimesN = (n, char) => Array(n + 1).join(char); 82function format(manifest, { 83 indentLevel = 2, 84 newline = _os().EOL 85} = {}) { 86 let xmlInput; 87 if (typeof manifest === 'string') { 88 xmlInput = manifest; 89 } else if (manifest.toString) { 90 var _manifest$resources3; 91 const builder = new (_xml2js().Builder)({ 92 headless: true 93 }); 94 95 // For strings.xml 96 if (Array.isArray(manifest === null || manifest === void 0 ? void 0 : (_manifest$resources3 = manifest.resources) === null || _manifest$resources3 === void 0 ? void 0 : _manifest$resources3.string)) { 97 for (const string of manifest === null || manifest === void 0 ? void 0 : (_manifest$resources4 = manifest.resources) === null || _manifest$resources4 === void 0 ? void 0 : _manifest$resources4.string) { 98 var _manifest$resources4; 99 if (string.$.translatable === 'false' || string.$.translatable === false) { 100 continue; 101 } 102 string._ = escapeAndroidString(string._); 103 } 104 } 105 xmlInput = builder.buildObject(manifest); 106 return xmlInput; 107 } else { 108 throw new Error(`Invalid XML value passed in: ${manifest}`); 109 } 110 const indentString = stringTimesN(indentLevel, ' '); 111 let formatted = ''; 112 const regex = /(>)(<)(\/*)/g; 113 const xml = xmlInput.replace(regex, `$1${newline}$2$3`); 114 let pad = 0; 115 xml.split(/\r?\n/).map(line => line.trim()).forEach(line => { 116 let indent = 0; 117 if (line.match(/.+<\/\w[^>]*>$/)) { 118 indent = 0; 119 } else if (line.match(/^<\/\w/)) { 120 if (pad !== 0) { 121 pad -= 1; 122 } 123 } else if (line.match(/^<\w([^>]*[^/])?>.*$/)) { 124 indent = 1; 125 } else { 126 indent = 0; 127 } 128 const padding = stringTimesN(pad, indentString); 129 formatted += padding + line + newline; 130 pad += indent; 131 }); 132 return formatted.trim(); 133} 134 135/** 136 * Escapes Android string literals, specifically characters `"`, `'`, `\`, `\n`, `\r`, `\t` 137 * 138 * @param value unescaped Android XML string literal. 139 */ 140function escapeAndroidString(value) { 141 value = value.replace(/[\n\r\t'"@]/g, m => { 142 switch (m) { 143 case '"': 144 case "'": 145 case '@': 146 return '\\' + m; 147 case '\n': 148 return '\\n'; 149 case '\r': 150 return '\\r'; 151 case '\t': 152 return '\\t'; 153 default: 154 throw new Error(`Cannot escape unhandled XML character: ${m}`); 155 } 156 }); 157 if (value.match(/(^\s|\s$)/)) { 158 value = '"' + value + '"'; 159 } 160 return value; 161} 162function unescapeAndroidString(value) { 163 return value.replace(/\\(.)/g, '$1'); 164} 165//# sourceMappingURL=XML.js.map