main.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.parse = exports.parseToExistingElement = exports.Absent = void 0;
  4. /**
  5. * Copyright (C) 2016-2020 Michael Kourlas
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. var xmlcreate_1 = require("xmlcreate");
  20. var options_1 = require("./options");
  21. var utils_1 = require("./utils");
  22. /**
  23. * Indicates that an object of a particular type should be suppressed from the
  24. * XML output.
  25. *
  26. * See the `typeHandlers` property in {@link IOptions} for more details.
  27. */
  28. var Absent = /** @class */ (function () {
  29. function Absent() {
  30. }
  31. Object.defineProperty(Absent, "instance", {
  32. /**
  33. * Returns the sole instance of Absent.
  34. */
  35. get: function () {
  36. return Absent._instance;
  37. },
  38. enumerable: false,
  39. configurable: true
  40. });
  41. Absent._instance = new Absent();
  42. return Absent;
  43. }());
  44. exports.Absent = Absent;
  45. /**
  46. * Gets the type handler associated with a value.
  47. */
  48. function getHandler(value, options) {
  49. var type = Object.prototype.toString.call(value);
  50. var handler;
  51. if (Object.prototype.hasOwnProperty.call(options.typeHandlers, "*")) {
  52. handler = options.typeHandlers["*"];
  53. }
  54. if (Object.prototype.hasOwnProperty.call(options.typeHandlers, type)) {
  55. handler = options.typeHandlers[type];
  56. }
  57. return handler;
  58. }
  59. /**
  60. * Parses a string into XML and adds it to the parent element or attribute.
  61. */
  62. function parseString(str, parentElement, options) {
  63. var requiresCdata = function (s) {
  64. return ((options.cdataInvalidChars &&
  65. (s.indexOf("<") !== -1 || s.indexOf("&") !== -1)) ||
  66. options.cdataKeys.indexOf(parentElement.name) !== -1 ||
  67. options.cdataKeys.indexOf("*") !== -1);
  68. };
  69. if (parentElement instanceof xmlcreate_1.XmlElement) {
  70. if (requiresCdata(str)) {
  71. var cdataStrs = str.split("]]>");
  72. for (var i = 0; i < cdataStrs.length; i++) {
  73. if (requiresCdata(cdataStrs[i])) {
  74. parentElement.cdata({
  75. charData: cdataStrs[i],
  76. replaceInvalidCharsInCharData: options.replaceInvalidChars,
  77. });
  78. }
  79. else {
  80. parentElement.charData({
  81. charData: cdataStrs[i],
  82. replaceInvalidCharsInCharData: options.replaceInvalidChars,
  83. });
  84. }
  85. if (i < cdataStrs.length - 1) {
  86. parentElement.charData({
  87. charData: "]]>",
  88. replaceInvalidCharsInCharData: options.replaceInvalidChars,
  89. });
  90. }
  91. }
  92. }
  93. else {
  94. parentElement.charData({
  95. charData: str,
  96. replaceInvalidCharsInCharData: options.replaceInvalidChars,
  97. });
  98. }
  99. }
  100. else {
  101. parentElement.text({
  102. charData: str,
  103. replaceInvalidCharsInCharData: options.replaceInvalidChars,
  104. });
  105. }
  106. }
  107. /**
  108. * Parses an attribute into XML and adds it to the parent element.
  109. */
  110. function parseAttribute(name, value, parentElement, options) {
  111. var attribute = parentElement.attribute({
  112. name: name,
  113. replaceInvalidCharsInName: options.replaceInvalidChars,
  114. });
  115. parseString((0, utils_1.stringify)(value), attribute, options);
  116. }
  117. /**
  118. * Parses an object or Map entry into XML and adds it to the parent element.
  119. */
  120. function parseObjectOrMapEntry(key, value, parentElement, options) {
  121. // Alias key
  122. if (key === options.aliasString) {
  123. parentElement.name = (0, utils_1.stringify)(value);
  124. return;
  125. }
  126. // Attributes key
  127. if (key.indexOf(options.attributeString) === 0 && (0, utils_1.isObject)(value)) {
  128. for (var _i = 0, _a = Object.keys(value); _i < _a.length; _i++) {
  129. var subkey = _a[_i];
  130. parseAttribute(subkey, (0, utils_1.stringify)(value[subkey]), parentElement, options);
  131. }
  132. return;
  133. }
  134. // Value key
  135. if (key.indexOf(options.valueString) === 0) {
  136. parseValue(key, (0, utils_1.stringify)(value), parentElement, options);
  137. return;
  138. }
  139. // Standard handling (create new element for entry)
  140. var element = parentElement;
  141. if (!(0, utils_1.isArray)(value) && !(0, utils_1.isSet)(value)) {
  142. // If handler for value returns absent, then do not add element
  143. var handler = getHandler(value, options);
  144. if (!(0, utils_1.isUndefined)(handler)) {
  145. if (handler(value) === Absent.instance) {
  146. return;
  147. }
  148. }
  149. element = parentElement.element({
  150. name: key,
  151. replaceInvalidCharsInName: options.replaceInvalidChars,
  152. useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
  153. });
  154. }
  155. parseValue(key, value, element, options);
  156. }
  157. /**
  158. * Parses an Object or Map into XML and adds it to the parent element.
  159. */
  160. function parseObjectOrMap(objectOrMap, parentElement, options) {
  161. if ((0, utils_1.isMap)(objectOrMap)) {
  162. objectOrMap.forEach(function (value, key) {
  163. parseObjectOrMapEntry((0, utils_1.stringify)(key), value, parentElement, options);
  164. });
  165. }
  166. else {
  167. for (var _i = 0, _a = Object.keys(objectOrMap); _i < _a.length; _i++) {
  168. var key = _a[_i];
  169. parseObjectOrMapEntry(key, objectOrMap[key], parentElement, options);
  170. }
  171. }
  172. }
  173. /**
  174. * Parses an array or Set into XML and adds it to the parent element.
  175. */
  176. function parseArrayOrSet(key, arrayOrSet, parentElement, options) {
  177. var arrayNameFunc;
  178. if (Object.prototype.hasOwnProperty.call(options.wrapHandlers, "*")) {
  179. arrayNameFunc = options.wrapHandlers["*"];
  180. }
  181. if (Object.prototype.hasOwnProperty.call(options.wrapHandlers, key)) {
  182. arrayNameFunc = options.wrapHandlers[key];
  183. }
  184. var arrayKey = key;
  185. var arrayElement = parentElement;
  186. if (!(0, utils_1.isUndefined)(arrayNameFunc)) {
  187. var arrayNameFuncKey = arrayNameFunc(arrayKey, arrayOrSet);
  188. if (!(0, utils_1.isNull)(arrayNameFuncKey)) {
  189. arrayKey = arrayNameFuncKey;
  190. arrayElement = parentElement.element({
  191. name: key,
  192. replaceInvalidCharsInName: options.replaceInvalidChars,
  193. useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
  194. });
  195. }
  196. }
  197. arrayOrSet.forEach(function (item) {
  198. var element = arrayElement;
  199. if (!(0, utils_1.isArray)(item) && !(0, utils_1.isSet)(item)) {
  200. // If handler for value returns absent, then do not add element
  201. var handler = getHandler(item, options);
  202. if (!(0, utils_1.isUndefined)(handler)) {
  203. if (handler(item) === Absent.instance) {
  204. return;
  205. }
  206. }
  207. element = arrayElement.element({
  208. name: arrayKey,
  209. replaceInvalidCharsInName: options.replaceInvalidChars,
  210. useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
  211. });
  212. }
  213. parseValue(arrayKey, item, element, options);
  214. });
  215. }
  216. /**
  217. * Parses an arbitrary JavaScript value into XML and adds it to the parent
  218. * element.
  219. */
  220. function parseValue(key, value, parentElement, options) {
  221. // If a handler for a particular type is user-defined, use that handler
  222. // instead of the defaults
  223. var handler = getHandler(value, options);
  224. if (!(0, utils_1.isUndefined)(handler)) {
  225. value = handler(value);
  226. }
  227. if ((0, utils_1.isObject)(value) || (0, utils_1.isMap)(value)) {
  228. parseObjectOrMap(value, parentElement, options);
  229. return;
  230. }
  231. if ((0, utils_1.isArray)(value) || (0, utils_1.isSet)(value)) {
  232. parseArrayOrSet(key, value, parentElement, options);
  233. return;
  234. }
  235. parseString((0, utils_1.stringify)(value), parentElement, options);
  236. }
  237. /**
  238. * Converts the specified object to XML and adds the XML representation to the
  239. * specified XmlElement object using the specified options.
  240. *
  241. * This function does not add a root element. In addition, it does not add an
  242. * XML declaration or DTD, and the associated options in {@link IOptions} are
  243. * ignored. If desired, these must be added manually.
  244. */
  245. function parseToExistingElement(element, object, options) {
  246. var opts = new options_1.Options(options);
  247. parseValue(element.name, object, element, opts);
  248. }
  249. exports.parseToExistingElement = parseToExistingElement;
  250. /**
  251. * Returns a XML string representation of the specified object using the
  252. * specified options.
  253. *
  254. * `root` is the name of the root XML element. When the object is converted
  255. * to XML, it will be a child of this root element.
  256. */
  257. function parse(root, object, options) {
  258. var opts = new options_1.Options(options);
  259. var document = new xmlcreate_1.XmlDocument({
  260. validation: opts.validation,
  261. });
  262. if (opts.declaration.include) {
  263. document.decl(opts.declaration);
  264. }
  265. if (opts.dtd.include) {
  266. document.dtd({
  267. // Validated in options.ts
  268. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  269. name: opts.dtd.name,
  270. pubId: opts.dtd.pubId,
  271. sysId: opts.dtd.sysId,
  272. });
  273. }
  274. var rootElement = document.element({
  275. name: root,
  276. replaceInvalidCharsInName: opts.replaceInvalidChars,
  277. useSelfClosingTagIfEmpty: opts.useSelfClosingTagIfEmpty,
  278. });
  279. parseToExistingElement(rootElement, object, options);
  280. return document.toString(opts.format);
  281. }
  282. exports.parse = parse;