UNPKG

16.2 kBJavaScriptView Raw
1(function (global, factory) {
2 if (typeof define === "function" && define.amd) {
3 define(["exports"], factory);
4 } else if (typeof exports !== "undefined") {
5 factory(exports);
6 } else {
7 var mod = {
8 exports: {}
9 };
10 factory(mod.exports);
11 global.jstoxml = mod.exports;
12 }
13})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) {
14 "use strict";
15
16 Object.defineProperty(_exports, "__esModule", {
17 value: true
18 });
19 _exports.default = _exports.toXML = void 0;
20
21 function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
22
23 function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
24
25 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
26
27 function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
28
29 function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
30
31 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
32
33 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
34
35 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
36
37 function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
38
39 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
40
41 var ARRAY = "array";
42 var BOOLEAN = "boolean";
43 var DATE = "date";
44 var NULL = "null";
45 var NUMBER = "number";
46 var OBJECT = "object";
47 var SPECIAL_OBJECT = "special-object";
48 var STRING = "string";
49 var PRIVATE_VARS = ["_selfCloseTag", "_attrs"];
50 var PRIVATE_VARS_REGEXP = new RegExp(PRIVATE_VARS.join("|"), "g");
51 /**
52 * Determines the indent string based on current tree depth.
53 */
54
55 var getIndentStr = function getIndentStr() {
56 var indent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
57 var depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
58 return indent.repeat(depth);
59 };
60 /**
61 * Sugar function supplementing JS's quirky typeof operator, plus some extra help to detect
62 * "special objects" expected by jstoxml.
63 * Example:
64 * getType(new Date());
65 * -> 'date'
66 */
67
68
69 var getType = function getType(val) {
70 return Array.isArray(val) && ARRAY || _typeof(val) === OBJECT && val !== null && val._name && SPECIAL_OBJECT || val instanceof Date && DATE || val === null && NULL || _typeof(val);
71 };
72 /**
73 * Replaces matching values in a string with a new value.
74 * Example:
75 * filterStr('foo&bar', { '&': '&amp;' });
76 * -> 'foo&amp;bar'
77 */
78
79
80 var filterStr = function filterStr() {
81 var inputStr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
82 var filter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
83
84 // Passthrough/no-op for nonstrings (e.g. number, boolean).
85 if (typeof inputStr !== "string") {
86 return inputStr;
87 }
88
89 var regexp = new RegExp("(".concat(Object.keys(filter).join("|"), ")(?!(\\w|#)*;)"), "g");
90 return String(inputStr).replace(regexp, function (str, entity) {
91 return filter[entity] || "";
92 });
93 };
94 /**
95 * Maps an object or array of arribute keyval pairs to a string.
96 * Examples:
97 * { foo: 'bar', baz: 'g' } -> 'foo="bar" baz="g"'
98 * [ { ⚡: true }, { foo: 'bar' } ] -> '⚡ foo="bar"'
99 */
100
101
102 var getAttributeKeyVals = function getAttributeKeyVals() {
103 var attributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
104 var filter = arguments.length > 1 ? arguments[1] : undefined;
105 var keyVals = [];
106
107 if (Array.isArray(attributes)) {
108 // Array containing complex objects and potentially duplicate attributes.
109 keyVals = attributes.map(function (attr) {
110 var key = Object.keys(attr)[0];
111 var val = attr[key];
112 var filteredVal = filter ? filterStr(val, filter) : val;
113 var valStr = filteredVal === true ? "" : "=\"".concat(filteredVal, "\"");
114 return "".concat(key).concat(valStr);
115 });
116 } else {
117 var keys = Object.keys(attributes);
118 keyVals = keys.map(function (key) {
119 // Simple object - keyval pairs.
120 // For boolean true, simply output the key.
121 var filteredVal = filter ? filterStr(attributes[key], filter) : attributes[key];
122 var valStr = attributes[key] === true ? "" : "=\"".concat(filteredVal, "\"");
123 return "".concat(key).concat(valStr);
124 });
125 }
126
127 return keyVals;
128 };
129 /**
130 * Converts an attributes object/array to a string of keyval pairs.
131 * Example:
132 * formatAttributes({ a: 1, b: 2 })
133 * -> 'a="1" b="2"'
134 */
135
136
137 var formatAttributes = function formatAttributes() {
138 var attributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
139 var filter = arguments.length > 1 ? arguments[1] : undefined;
140 var keyVals = getAttributeKeyVals(attributes, filter);
141 if (keyVals.length === 0) return "";
142 var keysValsJoined = keyVals.join(" ");
143 return " ".concat(keysValsJoined);
144 };
145 /**
146 * Converts an object to a jstoxml array.
147 * Example:
148 * objToArray({ foo: 'bar', baz: 2 });
149 * ->
150 * [
151 * {
152 * _name: 'foo',
153 * _content: 'bar'
154 * },
155 * {
156 * _name: 'baz',
157 * _content: 2
158 * }
159 * ]
160 */
161
162
163 var objToArray = function objToArray() {
164 var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
165 return Object.keys(obj).map(function (key) {
166 return {
167 _name: key,
168 _content: obj[key]
169 };
170 });
171 };
172 /**
173 * Determines if a value is a primitive JavaScript value (not including Symbol).
174 * Example:
175 * isPrimitive(4);
176 * -> true
177 */
178
179
180 var PRIMITIVE_TYPES = [STRING, NUMBER, BOOLEAN];
181
182 var isPrimitive = function isPrimitive(val) {
183 return PRIMITIVE_TYPES.includes(getType(val));
184 };
185 /**
186 * Determines if a value is a simple primitive type that can fit onto one line. Needed for
187 * determining any needed indenting and line breaks.
188 * Example:
189 * isSimpleType(new Date());
190 * -> true
191 */
192
193
194 var SIMPLE_TYPES = [].concat(PRIMITIVE_TYPES, [DATE, SPECIAL_OBJECT]);
195
196 var isSimpleType = function isSimpleType(val) {
197 return SIMPLE_TYPES.includes(getType(val));
198 };
199 /**
200 * Determines if an XML string is a simple primitive, or contains nested data.
201 * Example:
202 * isSimpleXML('<foo />');
203 * -> false
204 */
205
206
207 var isSimpleXML = function isSimpleXML(xmlStr) {
208 return !xmlStr.match("<");
209 };
210 /**
211 * Assembles an XML header as defined by the config.
212 */
213
214
215 var DEFAULT_XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';
216
217 var getHeaderString = function getHeaderString(_ref) {
218 var header = _ref.header,
219 indent = _ref.indent,
220 isOutputStart = _ref.isOutputStart;
221 var shouldOutputHeader = header && isOutputStart;
222 if (!shouldOutputHeader) return "";
223 var shouldUseDefaultHeader = _typeof(header) === BOOLEAN;
224 return "".concat(shouldUseDefaultHeader ? DEFAULT_XML_HEADER : header).concat(indent ? "\n" : "");
225 };
226 /**
227 * Recursively traverses an object tree and converts the output to an XML string.
228 * Example:
229 * toXML({ foo: 'bar' });
230 * -> <foo>bar</foo>
231 */
232
233
234 var defaultEntityFilter = {
235 "<": "&lt;",
236 ">": "&gt;",
237 "&": "&amp;"
238 };
239
240 var toXML = function toXML() {
241 var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
242 var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
243 var _config$depth = config.depth,
244 depth = _config$depth === void 0 ? 0 : _config$depth,
245 indent = config.indent,
246 _isFirstItem = config._isFirstItem,
247 header = config.header,
248 _config$attributesFil = config.attributesFilter,
249 rawAttributesFilter = _config$attributesFil === void 0 ? {} : _config$attributesFil,
250 _config$filter = config.filter,
251 rawFilter = _config$filter === void 0 ? {} : _config$filter;
252 var shouldTurnOffAttributesFilter = typeof rawAttributesFilter === 'boolean' && !rawAttributesFilter;
253 var attributesFilter = shouldTurnOffAttributesFilter ? {} : _objectSpread(_objectSpread(_objectSpread({}, defaultEntityFilter), {
254 '"': "&quot;"
255 }), rawAttributesFilter);
256 var shouldTurnOffFilter = typeof rawFilter === 'boolean' && !rawFilter;
257 var filter = shouldTurnOffFilter ? {} : _objectSpread(_objectSpread({}, defaultEntityFilter), rawFilter); // Determine indent string based on depth.
258
259 var indentStr = getIndentStr(indent, depth); // For branching based on value type.
260
261 var valType = getType(obj);
262 var isSimple = isSimpleType(obj); // Determine if this is the start of the output. Needed for header and indenting.
263
264 var isOutputStart = depth === 0 && (isSimple || !isSimple && _isFirstItem);
265 var outputStr = "";
266
267 switch (valType) {
268 case "special-object":
269 {
270 // Processes a specially-formatted object used by jstoxml.
271 var _name = obj._name,
272 _content = obj._content; // Output text content without a tag wrapper.
273
274 if (_content === null) {
275 outputStr = _name;
276 break;
277 } // Handles arrays of primitive values. (#33)
278
279
280 var isArrayOfPrimitives = Array.isArray(_content) && _content.every(isPrimitive);
281
282 if (isArrayOfPrimitives) {
283 return _content.map(function (a) {
284 return toXML({
285 _name: _name,
286 _content: a
287 }, _objectSpread(_objectSpread({}, config), {}, {
288 depth: depth
289 }));
290 }).join("");
291 } // Don't output private vars (such as _attrs).
292
293
294 if (_name.match(PRIVATE_VARS_REGEXP)) break; // Process the nested new value and create new config.
295
296 var newVal = toXML(_content, _objectSpread(_objectSpread({}, config), {}, {
297 depth: depth + 1
298 }));
299 var newValType = getType(newVal);
300 var isNewValSimple = isSimpleXML(newVal); // Pre-tag output (indent and line breaks).
301
302 var preIndentStr = indent && !isOutputStart ? "\n" : "";
303 var preTag = "".concat(preIndentStr).concat(indentStr); // Tag output.
304
305 var valIsEmpty = newValType === "undefined" || newVal === "";
306 var shouldSelfClose = _typeof(obj._selfCloseTag) === BOOLEAN ? valIsEmpty && obj._selfCloseTag : valIsEmpty;
307 var selfCloseStr = shouldSelfClose ? "/" : "";
308 var attributesString = formatAttributes(obj._attrs, attributesFilter);
309 var tag = "<".concat(_name).concat(attributesString).concat(selfCloseStr, ">"); // Post-tag output (closing tag, indent, line breaks).
310
311 var preTagCloseStr = indent && !isNewValSimple ? "\n".concat(indentStr) : "";
312 var postTag = !shouldSelfClose ? "".concat(newVal).concat(preTagCloseStr, "</").concat(_name, ">") : "";
313 outputStr = "".concat(preTag).concat(tag).concat(postTag);
314 break;
315 }
316
317 case "object":
318 {
319 // Iterates over keyval pairs in an object, converting each item to a special-object.
320 var keys = Object.keys(obj);
321 var outputArr = keys.map(function (key, index) {
322 var newConfig = _objectSpread(_objectSpread({}, config), {}, {
323 _isFirstItem: index === 0,
324 _isLastItem: index + 1 === keys.length
325 });
326
327 var outputObj = {
328 _name: key
329 };
330
331 if (getType(obj[key]) === "object") {
332 // Sub-object contains an object.
333 // Move private vars up as needed. Needed to support certain types of objects
334 // E.g. { foo: { _attrs: { a: 1 } } } -> <foo a="1"/>
335 PRIVATE_VARS.forEach(function (privateVar) {
336 var val = obj[key][privateVar];
337
338 if (typeof val !== "undefined") {
339 outputObj[privateVar] = val;
340 delete obj[key][privateVar];
341 }
342 });
343 var hasContent = typeof obj[key]._content !== "undefined";
344
345 if (hasContent) {
346 // _content has sibling keys, so pass as an array (edge case).
347 // E.g. { foo: 'bar', _content: { baz: 2 } } -> <foo>bar</foo><baz>2</baz>
348 if (Object.keys(obj[key]).length > 1) {
349 var newContentObj = Object.assign({}, obj[key]);
350 delete newContentObj._content;
351 outputObj._content = [].concat(_toConsumableArray(objToArray(newContentObj)), [obj[key]._content]);
352 }
353 }
354 } // Fallthrough: just pass the key as the content for the new special-object.
355
356
357 if (typeof outputObj._content === "undefined") outputObj._content = obj[key];
358 var xml = toXML(outputObj, newConfig, key);
359 return xml;
360 }, config);
361 var separator = indent && depth === 0 ? "\n" : "";
362 outputStr = outputArr.join(separator);
363 break;
364 }
365
366 case "function":
367 {
368 // Executes a user-defined function and return output.
369 var fnResult = obj(config);
370 outputStr = toXML(fnResult, config);
371 break;
372 }
373
374 case "array":
375 {
376 // Iterates and converts each value in an array.
377 var _outputArr = obj.map(function (singleVal, index) {
378 var newConfig = _objectSpread(_objectSpread({}, config), {}, {
379 _isFirstItem: index === 0,
380 _isLastItem: index + 1 === obj.length
381 });
382
383 return toXML(singleVal, newConfig);
384 });
385
386 var _separator = indent && depth === 0 ? "\n" : "";
387
388 outputStr = _outputArr.join(_separator);
389 break;
390 }
391 // number, string, boolean, date, null, etc
392
393 default:
394 {
395 outputStr = filterStr(obj, filter);
396 break;
397 }
398 }
399
400 var headerStr = getHeaderString({
401 header: header,
402 indent: indent,
403 depth: depth,
404 isOutputStart: isOutputStart
405 });
406 return "".concat(headerStr).concat(outputStr);
407 };
408
409 _exports.toXML = toXML;
410 var _default = {
411 toXML: toXML
412 };
413 _exports.default = _default;
414});