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