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