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