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