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