@adobe/acc-js-sdk 1.1.14 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -129,7 +129,7 @@ console.log(`About to call method '${methodName}' of scope '${scopeName}'`);
129
129
  returnedValue = undefined;
130
130
  }
131
131
  // If the API returns one parameter which is an object, the return it directly.
132
- // If not (return value is a litteral), then use a JSON with the return parameter name
132
+ // If not (return value is a literal), then use a JSON with the return parameter name
133
133
  else if (outNames.length == 1) {
134
134
  if (result && typeof result == "object")
135
135
  returnedValue = result;
@@ -2,6 +2,13 @@
2
2
  layout: page
3
3
  title: Change Log
4
4
  ---
5
+ <section class="changelog"><h1>Version 1.1.15</h1>
6
+ <h2>2022/11/28</h2>
7
+
8
+ <li>Fix an issue with SimpleJson serialization. See <a href="https://opensource.adobe.com/acc-js-sdk/simpleJson.html">SimpleJson documentation</a> for more details, and in particular the <b>Compatibility Notes</b> section</li>
9
+ <li>Fix credentials passing for fileUpload and getReportData methods. This is still a temporary fix until those APIs are made IMS compatible.</li>
10
+ </section>
11
+
5
12
  <section class="changelog"><h1>Version 1.1.14</h1>
6
13
  <h2>2022/11/25</h2>
7
14
 
@@ -202,7 +209,7 @@ For breaking changes see the [migration guide](MIGRATION.md)
202
209
  <li><b>getEntityIfMoreRecent</b> now takes an additional parameter which allows to specify and force a representation (xml, json...)
203
210
  <li>New helper function <b>DomUtil.isArray</b> to test if a JavaScript object is an array
204
211
  <li>New <b>EntityAccessor</b> object which allows to get attributes and child elements from xml or json objects, regardless of their representation
205
- <li>New <b>escapeXtk</b> function to escape litteral values in Xtk expression. Can be used as a function or as a tagged template litteral
212
+ <li>New <b>escapeXtk</b> function to escape literal values in Xtk expression. Can be used as a function or as a tagged template literal
206
213
  <li>New function <b>XtkCaster._variantStorageAttribute</b> which returns the name of a schema attribute used to store variant value types. The name of the attribute depends on the type: stringValue, longValue, etc.
207
214
  <li>Support for non static method that mutate the object on which they apply. For instance, the <b>xtk:queryDef#SelectAll</b>
208
215
  <li>Added samples in the samples/ folder
@@ -229,7 +236,7 @@ _Breaking changes in 1.0.0_
229
236
  <li>Changes in the <b>sdk.init</b>, <b>Client</b> constructor, and <b>logon</b> functions. Now using <b>ConnectionParameters</b> and <b>Credentials</b> objects to configure a Campaign connection
230
237
  <li>Client object members are now private: access to representation, etc. attributes is not allowed anymore except for <b>NLWS</b>, <b>XtkCaster</b>, and <b>DomUtil</b>
231
238
  <li>Access to the <b>sessionInfo</b> object after <b>logon</b> can be done via the new <b>getSessionInfo</b> call
232
- <li>Options cache internal strucutre change: option values in the cache are now object litterals containing the option value, type, and raw value (which may not be casted to the expected type yet)
239
+ <li>Options cache internal strucutre change: option values in the cache are now object literals containing the option value, type, and raw value (which may not be casted to the expected type yet)
233
240
  <li>Connecting to mid-sourcing (or other Campaign instances which are defined by an external account) is now done with the <b>ConnectionParameters.ofExternalAccount</b> function. As a consequence, <b>getSecretKeyCipher</b> is now private and deprecated
234
241
  <li>CampaignException object signature changed (but was not previously exposed)
235
242
  <li>The client-side bundle is now generated in the <b>dist/bundle.js</b> file instead of <b>bundle.js</b>
@@ -4,7 +4,7 @@ title: Escaping
4
4
  ---
5
5
 
6
6
 
7
- <p>It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded <b>ffda</b> name. The <b>expr</b> attribute takes an XTK expression as a parameter, and <b>ffda</b> is a string litteral in an xtk expression.</p>
7
+ <p>It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded <b>ffda</b> name. The <b>expr</b> attribute takes an XTK expression as a parameter, and <b>ffda</b> is a string literal in an xtk expression.</p>
8
8
 
9
9
  <p>To prevent xtk ingestions vulnerabilities, you should not concatenate strings and write code such as expr: "@name = '" + name + "'": if the value of the name
10
10
  parameter contains single quotes, your code will not work, but could also cause vulnerabilities.
@@ -13,19 +13,19 @@ title: Escaping
13
13
 
14
14
  <h1>sdk.escapeXtk</h1>
15
15
 
16
- <p>The <b>sdk.escapeXtk</b> can be used to properly escape string litterals in xtk expressions. The function will also surround the escaped value with single quotes.</p>
16
+ <p>The <b>sdk.escapeXtk</b> can be used to properly escape string literals in xtk expressions. The function will also surround the escaped value with single quotes.</p>
17
17
 
18
18
  <p>You can use string concatenation like this. Note the lack of single quotes around the value.</p>
19
19
  <pre class="code">
20
20
  { expr: "@name=" + sdk.escapeXtk(name) }
21
21
  </pre>
22
22
 
23
- <p>or a template litteral</p>
23
+ <p>or a template literal</p>
24
24
  <pre class="code">
25
25
  `{ expr: "@name=${sdk.escapeXtk(name)}" }`
26
26
  </pre>
27
27
 
28
- <p>The <b>escapeXtk</b> function can also be used to create tagged string litterals. This leads to a much shorter syntax. Note that with this syntax, only the parameter values of the template litteral are escaped</p>
28
+ <p>The <b>escapeXtk</b> function can also be used to create tagged string literals. This leads to a much shorter syntax. Note that with this syntax, only the parameter values of the template literal are escaped</p>
29
29
  <pre class="code">
30
30
  sdk.escapeXtk`{ expr: "@name=${name}" }`
31
31
  </pre>
@@ -4,7 +4,7 @@ title: SimpleJson format
4
4
  ---
5
5
 
6
6
  <p>The <b>SimpleJson</b> format is the format used by default by the SDK to conver between Campaign XML and JSON</p>
7
-
7
+ <p></p>
8
8
 
9
9
  <ul>
10
10
  <li>XML attributes are JSON properties (without the “@” sign)</li>
@@ -27,6 +27,7 @@ title: SimpleJson format
27
27
  </pre>
28
28
 
29
29
 
30
+ <h1>XML Root</h1>
30
31
  <p>The XML root element tag is automatically determined by the SDK as it's generating the XML, usually from the current schema name.</p>
31
32
 
32
33
  <pre class="code">
@@ -34,15 +35,21 @@ XML: &lt;root/>
34
35
  JSON: {}
35
36
  </pre>
36
37
 
37
- <p>XML attributes are mapped to JSON attributes with the same name, whose litteral value can be a string, number, or boolean. There's no "@" sign in the JSON attribute name.
38
- Values in JSON attributes can be indifferently typed (ex: number, boolean), or strings (ex: "3" instead of just 3) depending if the conversion could determine the attribute type or not.
39
- API users should expect and handle both value and use the `XtkCaster` object to ensure proper conversion when using.</p>
38
+
39
+
40
+
41
+ <h1>XML Attributes</h1>
42
+ <p>XML attributes are mapped to JSON attributes with the same name, whose literal value can be a string, number, or boolean. There's no "@" sign in the JSON attribute name.
43
+ Values in JSON attributes can be either typed (ex: number, boolean), or strings (ex: "3" instead of just 3) depending if the conversion could determine the attribute type or not.
44
+ API users should expect and handle both value and use the <b>XtkCaster</b> object to ensure proper conversion.</p>
40
45
 
41
46
  <pre class="code">
42
47
  XML &lt;root hello="world" count="3" ok="true"/>
43
48
  JSON: { hello:"world", count:"3", ok:"true" }
44
49
  </pre>
45
50
 
51
+
52
+ <h1>XML Elements</h1>
46
53
  <p>XML elements are mapped to JSON objects</p>
47
54
 
48
55
  <pre class="code">
@@ -64,7 +71,9 @@ XML: &lt;root>&lt;item id=1/>&lt;item id=2/>&lt;/root>
64
71
  JSON: { item: [ { id:"1" }, { id:"2" } ] }
65
72
  </pre>
66
73
 
67
- <p>Text of XML element is handle with the <b>$</b> sign in the JSON attribute name, or with a child JSON object name <b>$</b></p>
74
+
75
+ <h1>Text nodes</h1>
76
+ <p>Text of XML element is handled with the <b>$</b> sign in the JSON attribute name, or with a child JSON object name <b>$</b></p>
68
77
 
69
78
  <p>Text of the root element</p>
70
79
  <pre class="code">
@@ -86,3 +95,67 @@ XML: &lt;root>&lt;item>Hello&lt;child id="1"/>
86
95
  &lt;/root>
87
96
  JSON: { item: { $: "Hello", child: { id:"1" } }
88
97
  </pre>
98
+
99
+ <p>Normally Campaign will not generate XML with elements containing multiple sibling text nodes. If this should happen, the SDK will consider them as a single text value, i.e. it will concatenate the contents of each text and CDATA node as if there was only one. However, whitespaces are processed independently for each text node.
100
+ </p>
101
+
102
+ <h1>Whitespaces</h1>
103
+ <p>In XML documents, whitespaces can be either significant or insignificant. The SDK uses the following rules to strip whitespaces, which correspond to how Campaign specifically uses XML</p>
104
+ <p> </p>
105
+ <ul>
106
+ <li>The characters " ", "\t", "\r" and "\n" are considered whitespaces</li>
107
+ <li>CDATA sections are kept unchanged, i.e. whitespaces are preserved exactly</li>
108
+ <li>For TEXT nodes directly under the root node are, whitespaces will be trimmed as explained below</li>
109
+ <li>For element nodes which only contain text and possibly attributes (for instance &lt;node&gt;value&lt;/node&gt;</li>, the text is kept unchanged, i.e. whitespaces are preserved exactly</li>
110
+ <li>For element nodes which have child elements, whitespaces will be trimmed as explained below</li>
111
+ <li>For the root element, whitespaces are always trimmed</li>
112
+ </ul>
113
+ <p> </p>
114
+ <p>
115
+ Whitespace trimming consists of removing all the leading and trailing whitespaces of each text node and concatenating all text node values. If the resulting value is empty, the text node is ignored. The rationale is to remove insignificant spaces created when formatting XML documents
116
+ </p>
117
+
118
+
119
+ <h1>Exceptions</h1>
120
+
121
+ <h2>When an attribute has the same name of an element</h2>
122
+
123
+ <p>If an element contains another element and an attribute which have the same name, the attribute name is prefixed with the "@" character</p>
124
+ <pre class="code">
125
+ XML: &lt;root timezone="Europe/Paris">
126
+ &lt;timezone>Europe/Paris&lt;/timezone>
127
+ &lt;/root>
128
+ JSON: { "@timezone": "Europe/Paris",
129
+ timezone: { "$": "Europe/Paris" } }
130
+ </pre>
131
+
132
+
133
+ <h1>Arrays of text elements</h1>
134
+ <p></p>
135
+ <pre class="code">
136
+ XML: &lt;root>
137
+ &lt;item>One&lt;/item>
138
+ &lt;item>Two&lt;/item>
139
+ &lt;/root>
140
+ JSON: { item: [
141
+ { $: "One" },
142
+ { $: "Two" }
143
+ ] }
144
+ </pre>
145
+
146
+
147
+
148
+ <h1>Compatibility notes</h1>
149
+
150
+ <p>
151
+ A few gaps were identified regarding SimpleJson format when converting from XML to JSON. They were fixed in release 1.1.15 and may introduce some behavior changes for cases which were ambiguous
152
+ </p>
153
+ <p> </p>
154
+ <ul>
155
+ <li>When XML element has both a text content and attributes or child elements</li>
156
+ <li>When root element has only text</li>
157
+ <li>When XML element has both an attribute and a child element with the same name</li>
158
+ <li>When array contains element which only have text</li>
159
+ <li>When XML is formatted (and therefore has insignificant whitespaces)</li>
160
+ <li>XML collections (i.e. when root node ends with “-collection”) would sometimes contain a JSON property “#text”</li>
161
+ </ul>
@@ -27,7 +27,7 @@ title: The Transport Protocol
27
27
 
28
28
  <p>If the request is successful, a promise is returned with the result payload, as a string.</p>
29
29
 
30
- <p>If the request fails, the promise is rejected with an error object with class <b>HttpError</b>, a litteral with the following attributes:</p>
30
+ <p>If the request fails, the promise is rejected with an error object with class <b>HttpError</b>, a literal with the following attributes:</p>
31
31
  <ul>
32
32
  <li><b>statusCode</b> is the HTTP status code, such as 404, 500, etc.</li>
33
33
  <li><b>statusText</b> is the HTTP status text coming with the error</li>
@@ -39,7 +39,7 @@ title: The Transport Protocol
39
39
  <p>The transport can be overriden by using the <b>client.setTransport</b> call and passing it a transport function, i.e. an async function which</p>
40
40
 
41
41
  <ul>
42
- <li>Takes a <b>Request</b> object litteral as a parameter</li>
42
+ <li>Takes a <b>Request</b> object literal as a parameter</li>
43
43
  <li>Returns a the request result in a promise</li>
44
44
  <li>Returns a rejected promise containing an <b>HttpError</b> in case of failure</li>
45
45
  </ul>
@@ -74,7 +74,7 @@ const extAccount = await query.executeQuery();
74
74
 
75
75
 
76
76
  <h1>Escaping</h1>
77
- <p>It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded <b>ffda</b> name. The <b>expr</b> attribute takes an XTK expression as a parameter, and <b>ffda</b> is a string litteral in an xtk expression.</p>
77
+ <p>It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded <b>ffda</b> name. The <b>expr</b> attribute takes an XTK expression as a parameter, and <b>ffda</b> is a string literal in an xtk expression.</p>
78
78
 
79
79
  <p>To prevent xtk ingestions vulnerabilities, you should not concatenate strings and write code such as expr: "@name = '" + name + "'": if the value of the name
80
80
  parameter contains single quotes, your code will not work, but could also cause vulnerabilities.
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/acc-js-sdk",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/acc-js-sdk",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "ACC Javascript SDK",
5
5
  "main": "src/index.js",
6
6
  "homepage": "https://github.com/adobe/acc-js-sdk#readme",
package/src/campaign.js CHANGED
@@ -28,7 +28,7 @@ const { Util } = require("./util.js");
28
28
  static INVALID_CREDENTIALS_TYPE(type, details) { return new CampaignException(undefined, 400, 16384, `SDK-000000 Invalid credentials type '${type}'`, details); }
29
29
  static CANNOT_GET_CREDENTIALS_USER(type) { return new CampaignException(undefined, 400, 16384, `SDK-000001 Cannot get user for Credentials of type '${type}'`); }
30
30
  static CANNOT_GET_CREDENTIALS_PASSWORD(type) { return new CampaignException(undefined, 400, 16384, `SDK-000002 Cannot get password for Credentials of type '${type}'`); }
31
- static INVALID_CONNECTION_OPTIONS(options) { return new CampaignException(undefined, 400, 16384, `SDK-000003 Invalid options parameter (type '${typeof options}'). An object litteral is expected`); }
31
+ static INVALID_CONNECTION_OPTIONS(options) { return new CampaignException(undefined, 400, 16384, `SDK-000003 Invalid options parameter (type '${typeof options}'). An object literal is expected`); }
32
32
  static INVALID_REPRESENTATION(representation, details) { return new CampaignException(undefined, 400, 16384, `SDK-000004 Invalid representation '${representation}'.`, details); }
33
33
  static CREDENTIALS_FOR_INVALID_EXT_ACCOUNT(name, type) { return new CampaignException(undefined, 400, 16384, `SDK-000005 Cannot created connection parameters for external account '${name}': account type ${type} not supported`); }
34
34
  static BAD_PARAMETER(name, value, details) { return new CampaignException(undefined, 400, 16384, `SDK-000006 Bad parameter '${name}' with value '${value}'`, details); }
package/src/client.js CHANGED
@@ -546,16 +546,14 @@ const fileUploader = (client) => {
546
546
  }
547
547
  const data = new FormData();
548
548
  data.append('file_noMd5', file);
549
- //TODO: Needs to be refactored after cookie issue get resolved.
550
549
  client._makeHttpCall({
551
550
  url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
552
551
  processData: false,
553
- credentials: 'include',
554
552
  method: 'POST',
555
553
  data: data,
556
554
  headers: {
557
- 'x-security-token': client._securityToken,
558
- 'Cookie': '__sessiontoken=' + client._sessionToken,
555
+ 'X-Security-Token': client._securityToken,
556
+ 'X-Session-Token': client._sessionToken,
559
557
  }
560
558
  }).then((okay) => {
561
559
  if (!okay.startsWith('Ok')) {
@@ -1794,11 +1792,10 @@ class Client {
1794
1792
  url: `${this._connectionParameters._endpoint}/report/${callContext.reportName}?${encodeURI(`_noRender=true&_schema=${callContext.schema}&_context=${callContext.context}&_selection=${callContext.selection}`)}&_selectionCount=${selectionCount}`,
1795
1793
  headers: {
1796
1794
  'X-Security-Token': this._securityToken,
1797
- 'Cookie': '__sessiontoken=' + this._sessionToken,
1795
+ 'X-Session-Token': this._sessionToken,
1798
1796
  'Content-Type': 'application/x-www-form-urlencoded'
1799
1797
  },
1800
1798
  method: 'POST',
1801
- credentials: 'include',
1802
1799
  data : qsStringify(callContext.formData)
1803
1800
  };
1804
1801
 
package/src/domUtil.js CHANGED
@@ -386,6 +386,7 @@ class DomUtil {
386
386
  static _getTextIfTextNode(xml) {
387
387
  const child = xml.firstChild;
388
388
  if (!child) return null; // no children
389
+ if (xml.hasAttributes()) return null; // no attributes
389
390
  if (child.nextSibling) return null; // more than 1 child
390
391
  if (child.nodeType !== 3 && child.nodeType !== 4) return null;
391
392
  const text = child.nodeValue;
@@ -400,29 +401,37 @@ class DomUtil {
400
401
  * @param {Element} xml the DOM element to convert to JSON
401
402
  * @param {Object} json the object literal to write to
402
403
  * @param {string} flavor the JSON flavor: "SimpleJson" or "BadgerFish"
404
+ * @param {Object} parentJson parent JSON node during recursion. Is undefined for first call
405
+ * @param {boolean} forceTextAs is set during recursion (SimpleJson format) to force serialization of text nodes using "$: value" syntax
406
+ * instead of "$name: value" syntax. This is necessary to process collections and arrays of elements which only
407
+ * contain text nodes.
403
408
  */
404
- static _toJSON(xml, json, flavor) {
405
- if (xml.hasAttributes()) {
406
- var attributes = xml.attributes;
407
- for (var i=0; i<attributes.length; i++) {
408
- var att = attributes[i];
409
- var attName = (flavor == "BadgerFish" ? "@" : "") + att.name;
410
- json[attName] = att.value;
411
- }
412
- }
409
+ static _toJSON(xml, json, flavor, parentJson, forceTextAs$) {
413
410
 
414
411
  // Heuristic to determine if element is an object or an array
415
412
  const isCollection = xml.tagName.length > 11 && xml.tagName.substr(xml.tagName.length-11) == '-collection';
416
413
 
414
+ // Figure out which elements are arrays. Keep a count of elements for each tag name.
415
+ // When count >1 we consider this tag name to be an array
416
+ var hasChildElements = false; // Will be set if there is at least one child element
417
+ const countByTag = {};
417
418
  var child = xml.firstChild;
418
419
  while (child) {
419
- var childName = child.nodeName;
420
- if (isCollection && (json[childName] === null || json[childName] === undefined))
421
- json[childName] = [ ];
422
- var isArray = !!json[childName];
423
- if (isArray && !Util.isArray(json[childName]))
424
- json[childName] = [ json[childName] ];
425
- if (child.nodeType == 1) { // element
420
+ if (child.nodeType == 1) {
421
+ const childName = child.nodeName;
422
+ if (countByTag[childName] === undefined) countByTag[childName] = 1;
423
+ else countByTag[childName] = countByTag[childName] + 1;
424
+ hasChildElements = true;
425
+ }
426
+ child = child.nextSibling;
427
+ }
428
+
429
+ child = xml.firstChild;
430
+ while (child) {
431
+ if (child.nodeType == 1) {
432
+ const childName = child.nodeName;
433
+ const isArray = isCollection || countByTag[childName] > 1;
434
+ if (isArray && !json[childName]) json[childName] = [];
426
435
  // In SimpleJson representation, ensure we have proper transformation
427
436
  // of text and CDATA nodes. For instance, the following
428
437
  // <workflow><desc>Hello</desc></workflow>
@@ -434,12 +443,12 @@ class DomUtil {
434
443
  // from the schema, we cannot know if <desc></desc> should be
435
444
  // transformed into "$desc": "" or into "desc": {}
436
445
  const text = this._getTextIfTextNode(child);
437
- if (text !== null && flavor == "SimpleJson") {
446
+ if (!isArray && text !== null && flavor == "SimpleJson") {
438
447
  json[`$${childName}`] = text;
439
448
  }
440
449
  else {
441
450
  const jsonChild = flavor == "BadgerFish" ? new BadgerFishObject() : {};
442
- this._toJSON(child, jsonChild, flavor);
451
+ this._toJSON(child, jsonChild, flavor, json, isArray);
443
452
  if (isArray)
444
453
  json[childName].push(jsonChild);
445
454
  else
@@ -457,6 +466,46 @@ class DomUtil {
457
466
  }
458
467
  child = child.nextSibling;
459
468
  }
469
+
470
+ // Proceed with text nodes in SimpleJson format.
471
+ if (flavor === "SimpleJson") {
472
+ var text = "";
473
+ child = xml.firstChild;
474
+ while (child) {
475
+ if (child.nodeType === 3) { // text
476
+ var nodeText = child.nodeValue;
477
+ // Whitespace trimming rule: always trim for the root node, and trim for non-root nodes
478
+ // which actually have children elements
479
+ // Never trim CDATA nodes (nodeType 4)
480
+ if (!parentJson || hasChildElements)
481
+ nodeText = nodeText.trim();
482
+ if (nodeText) text = text + nodeText;
483
+ }
484
+ else if (child.nodeType === 4) { // CDATA
485
+ const cdataText = child.nodeValue;
486
+ if (cdataText) text = text + cdataText;
487
+ }
488
+ child = child.nextSibling;
489
+ }
490
+ if (text) {
491
+ json.$ = text;
492
+ }
493
+ }
494
+
495
+ // Finally proceed with attributes. They are processed last so that we get a chance to prefix
496
+ // the attribute name with "@" in SimpleJson format if there's already an element with the
497
+ // same name
498
+ if (xml.hasAttributes()) {
499
+ const attributes = xml.attributes;
500
+ for (var i=0; i<attributes.length; i++) {
501
+ const att = attributes[i];
502
+ var attName = (flavor == "BadgerFish" ? "@" : "") + att.name;
503
+ if (json[attName] !== undefined && flavor === "SimpleJson")
504
+ // There's already an element with the same name as the attribute
505
+ attName = "@" + attName;
506
+ json[attName] = att.value;
507
+ }
508
+ }
460
509
  }
461
510
 
462
511
  /**
package/src/index.js CHANGED
@@ -112,15 +112,15 @@ class SDK {
112
112
  * There are 2 alternate signatures for this function
113
113
  * <ul>
114
114
  * <li> the first one takes one single parameter which is a string and returns the escaped, quoted string
115
- * <li> the second one takes 2 array of strings and is called when using the function in tagged string litterals. The first array is the constant parts
116
- * of the string litteral, and the second array contains the variable parts. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
115
+ * <li> the second one takes 2 array of strings and is called when using the function in tagged string literals. The first array is the constant parts
116
+ * of the string literal, and the second array contains the variable parts. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
117
117
  * </ul>
118
118
  * <p>
119
- * The function can be used in a tagged string litterals like this: "var expr = escapeXtk`@name=${hello}`"
119
+ * The function can be used in a tagged string literals like this: "var expr = escapeXtk`@name=${hello}`"
120
120
  * <p>
121
121
  * @memberof Campaign
122
- * @param {string|string[]} p1 is the text to escape. If the text is null or undefined, it will be handled as an empty string. when using the escapeXtk for a tagged string litteral, this parameter is the array of constant values in the template.
123
- * @param {undefined|string[]} p2 when using the escapeXtk for a tagged string litteral, this parameter is the array of expression values in the template.
122
+ * @param {string|string[]} p1 is the text to escape. If the text is null or undefined, it will be handled as an empty string. when using the escapeXtk for a tagged string literal, this parameter is the array of constant values in the template.
123
+ * @param {undefined|string[]} p2 when using the escapeXtk for a tagged string literal, this parameter is the array of expression values in the template.
124
124
  * @returns {string} the escaped and quoted (simple quotes) text.
125
125
  *
126
126
  * @example
@@ -138,7 +138,7 @@ class SDK {
138
138
  return "'" + String(p1).replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'";
139
139
  }
140
140
 
141
- // Second syntax: for use in tagged template litterals
141
+ // Second syntax: for use in tagged template literals
142
142
  // instead of writing: { expr: "@name = " + escapeXtk(userName) }
143
143
  // you write { expr: escapeXtk`@name = {userName}` }
144
144
  if (p1.length == 0) return "''";
package/src/soap.js CHANGED
@@ -85,7 +85,7 @@ const NS_XSD = "http://www.w3.org/2001/XMLSchema";
85
85
  class SoapMethodCall {
86
86
 
87
87
  constructor(transport, urn, methodName, sessionToken, securityToken, userAgentString, pushDownOptions, extraHttpHeaders) {
88
- this.request = undefined; // The HTTP request (object litteral passed to the transport layer)
88
+ this.request = undefined; // The HTTP request (object literal passed to the transport layer)
89
89
  this.requestOptions = undefined;
90
90
  this.response = undefined; // The HTTP response object (in case of success)
91
91
 
package/src/transport.js CHANGED
@@ -114,7 +114,6 @@ if (!Util.isBrowser()) {
114
114
  method: options.method,
115
115
  headers: headers,
116
116
  body: options.data,
117
- credentials: options.credentials || 'same-origin'
118
117
  });
119
118
 
120
119
  const p = fetch(r).then(async (response) => {
package/src/util.js CHANGED
@@ -55,7 +55,7 @@ class Util {
55
55
  // JavaScript arrays are objects
56
56
  if (typeof obj != "object") return false;
57
57
  // They also have a length property. But checking the length is not enough
58
- // since, it can also be an object litteral with a "length" property. Campaign
58
+ // since, it can also be an object literal with a "length" property. Campaign
59
59
  // schema attributes typically have a "length" attribute and are not arrays
60
60
  if (obj.length === undefined || obj.length === null) return false;
61
61
  // So check for a "push" function
@@ -40,14 +40,14 @@ describe('ACC Client', function () {
40
40
  it('Create client with invalid parameters', () => {
41
41
  // No 4th parameter should be ok
42
42
  expect(new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin"))).not.toBeFalsy();
43
- // Object litteral is ok too
43
+ // Object literal is ok too
44
44
  expect(new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin"), {})).not.toBeFalsy();
45
45
  expect(new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin"), { representation: "BadgerFish" })).not.toBeFalsy();
46
46
  expect(new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin"), { dummy: 1 })).not.toBeFalsy();
47
47
  // Boolean is not ok
48
- expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", true)); }).toThrow("An object litteral is expected");
49
- expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", false)); }).toThrow("An object litteral is expected");
50
- expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", "BadgerFish")); }).toThrow("An object litteral is expected");
48
+ expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", true)); }).toThrow("An object literal is expected");
49
+ expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", false)); }).toThrow("An object literal is expected");
50
+ expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", "BadgerFish")); }).toThrow("An object literal is expected");
51
51
  // Invalid representation is not ok
52
52
  expect(() => { new Client(sdk, ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", { representation: "Hello" })); }).toThrow("Invalid representation");
53
53
  });
@@ -2614,7 +2614,7 @@ describe('ACC Client', function () {
2614
2614
  </extAccount-collection>`);
2615
2615
  });
2616
2616
 
2617
- it("Should force an json representation", async () => {
2617
+ it("Should force a json representation", async () => {
2618
2618
  const client = await Mock.makeClient();
2619
2619
  client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
2620
2620
  await client.NLWS.xtkSession.logon();
@@ -2633,7 +2633,7 @@ describe('ACC Client', function () {
2633
2633
  const query = client.NLWS.json.xtkQueryDef.create(queryDef);
2634
2634
  const result = await query.executeQuery();
2635
2635
  const json = JSON.stringify(result);
2636
- expect(json).toBe('{"#text":[],"extAccount":[{"id":"1816","name":"defaultPopAccount"},{"id":"1818","name":"defaultOther"},{"id":"1849","name":"billingReport"},{"id":"12070","name":"TST_EXT_ACCOUNT_POSTGRESQL"},{"id":"1817","name":"defaultEmailBulk"},{"id":"2087","name":"ffda"},{"id":"2088","name":"defaultEmailMid"}]}');
2636
+ expect(json).toBe('{"extAccount":[{"id":"1816","name":"defaultPopAccount"},{"id":"1818","name":"defaultOther"},{"id":"1849","name":"billingReport"},{"id":"12070","name":"TST_EXT_ACCOUNT_POSTGRESQL"},{"id":"1817","name":"defaultEmailBulk"},{"id":"2087","name":"ffda"},{"id":"2088","name":"defaultEmailMid"}]}');
2637
2637
  });
2638
2638
  });
2639
2639
 
@@ -3252,8 +3252,10 @@ describe('ACC Client', function () {
3252
3252
  url: expect.any(String),
3253
3253
  method: 'POST',
3254
3254
  processData: false,
3255
- credentials: 'include',
3256
- headers: expect.anything(),
3255
+ headers: expect.objectContaining({
3256
+ 'X-Security-Token': expect.any(String),
3257
+ 'X-Session-Token': expect.any(String),
3258
+ }),
3257
3259
  })
3258
3260
  );
3259
3261
 
@@ -3514,6 +3516,18 @@ describe('ACC Client', function () {
3514
3516
  schema: "nms:delivery",
3515
3517
  formData: {ctx: {}}
3516
3518
  });
3519
+ expect(client._transport).toHaveBeenLastCalledWith(
3520
+ expect.objectContaining({
3521
+ data: expect.anything(),
3522
+ url: expect.any(String),
3523
+ method: 'POST',
3524
+ headers: expect.objectContaining({
3525
+ 'X-Security-Token': expect.any(String),
3526
+ 'X-Session-Token': expect.any(String),
3527
+ "Content-Type": "application/x-www-form-urlencoded",
3528
+ }),
3529
+ })
3530
+ );
3517
3531
  expect(report._reportContext).toBe("throughput");
3518
3532
  expect(report._selection).toBe("12133");
3519
3533
  expect(report.vars.$period).toBe("604800");
@@ -144,17 +144,19 @@ describe('DomUtil', function() {
144
144
  return DomUtil.toXMLString(xml);
145
145
  }
146
146
 
147
- assert.strictEqual(fromJSON({}), '<root/>');
148
- assert.strictEqual(fromJSON({ "a":2, "b":"zz", "c": true }), '<root a="2" b="zz" c="true"/>');
149
- assert.strictEqual(fromJSON({ "a":{ x:3 } }), '<root><a x="3"/></root>');
150
- assert.strictEqual(fromJSON({ "$": "Hello" }), '<root>Hello</root>');
151
- assert.strictEqual(fromJSON({ "$a": "Hello" }), '<root><a>Hello</a></root>');
152
- assert.strictEqual(fromJSON({ a: { "$": "Hello" } }), '<root><a>Hello</a></root>');
153
- assert.strictEqual(fromJSON({ a: "World", "$a": "Hello" }), '<root a="World"><a>Hello</a></root>');
154
- assert.strictEqual(fromJSON({ "a": [ { "i":1 }, { "i": 2 } ] }), '<root><a i="1"/><a i="2"/></root>');
155
- assert.strictEqual(fromJSON({ "a": [ ] }), '<root/>');
156
- assert.strictEqual(fromJSON({ "a": null }), '<root/>');
157
- assert.strictEqual(fromJSON({ "a": undefined }), '<root/>');
147
+ it("Should convert from JSON to XML", () => {
148
+ assert.strictEqual(fromJSON({}), '<root/>');
149
+ assert.strictEqual(fromJSON({ "a":2, "b":"zz", "c": true }), '<root a="2" b="zz" c="true"/>');
150
+ assert.strictEqual(fromJSON({ "a":{ x:3 } }), '<root><a x="3"/></root>');
151
+ assert.strictEqual(fromJSON({ "$": "Hello" }), '<root>Hello</root>');
152
+ assert.strictEqual(fromJSON({ "$a": "Hello" }), '<root><a>Hello</a></root>');
153
+ assert.strictEqual(fromJSON({ a: { "$": "Hello" } }), '<root><a>Hello</a></root>');
154
+ assert.strictEqual(fromJSON({ a: "World", "$a": "Hello" }), '<root a="World"><a>Hello</a></root>');
155
+ assert.strictEqual(fromJSON({ "a": [ { "i":1 }, { "i": 2 } ] }), '<root><a i="1"/><a i="2"/></root>');
156
+ assert.strictEqual(fromJSON({ "a": [ ] }), '<root/>');
157
+ assert.strictEqual(fromJSON({ "a": null }), '<root/>');
158
+ assert.strictEqual(fromJSON({ "a": undefined }), '<root/>');
159
+ });
158
160
  });
159
161
 
160
162
  describe('fromJSON (default)', function() {
@@ -164,17 +166,37 @@ describe('DomUtil', function() {
164
166
  return DomUtil.toXMLString(xml);
165
167
  }
166
168
 
167
- assert.strictEqual(fromJSON({}), '<root/>');
168
- assert.strictEqual(fromJSON({ "a":2, "b":"zz", "c": true }), '<root a="2" b="zz" c="true"/>');
169
- assert.strictEqual(fromJSON({ "a":{ x:3 } }), '<root><a x="3"/></root>');
170
- assert.strictEqual(fromJSON({ "$": "Hello" }), '<root>Hello</root>');
171
- assert.strictEqual(fromJSON({ "$a": "Hello" }), '<root><a>Hello</a></root>');
172
- assert.strictEqual(fromJSON({ a: { "$": "Hello" } }), '<root><a>Hello</a></root>');
173
- assert.strictEqual(fromJSON({ a: "World", "$a": "Hello" }), '<root a="World"><a>Hello</a></root>');
174
- assert.strictEqual(fromJSON({ "a": [ { "i":1 }, { "i": 2 } ] }), '<root><a i="1"/><a i="2"/></root>');
175
- assert.strictEqual(fromJSON({ "a": [ ] }), '<root/>');
176
- assert.strictEqual(fromJSON({ "a": null }), '<root/>');
177
- assert.strictEqual(fromJSON({ "a": undefined }), '<root/>');
169
+ it("Should convert from JSON to XML", () => {
170
+ assert.strictEqual(fromJSON({}), '<root/>');
171
+ assert.strictEqual(fromJSON({ "a":2, "b":"zz", "c": true }), '<root a="2" b="zz" c="true"/>');
172
+ assert.strictEqual(fromJSON({ "a":{ x:3 } }), '<root><a x="3"/></root>');
173
+ assert.strictEqual(fromJSON({ "$": "Hello" }), '<root>Hello</root>');
174
+ assert.strictEqual(fromJSON({ "$a": "Hello" }), '<root><a>Hello</a></root>');
175
+ assert.strictEqual(fromJSON({ a: { "$": "Hello" } }), '<root><a>Hello</a></root>');
176
+ assert.strictEqual(fromJSON({ a: "World", "$a": "Hello" }), '<root a="World"><a>Hello</a></root>');
177
+ assert.strictEqual(fromJSON({ "a": [ { "i":1 }, { "i": 2 } ] }), '<root><a i="1"/><a i="2"/></root>');
178
+ assert.strictEqual(fromJSON({ "a": [ ] }), '<root/>');
179
+ assert.strictEqual(fromJSON({ "a": null }), '<root/>');
180
+ assert.strictEqual(fromJSON({ "a": undefined }), '<root/>');
181
+ });
182
+ });
183
+
184
+ describe('fromJSON (advanced)', function() {
185
+ function fromJSON(json) {
186
+ var xml = DomUtil.fromJSON("root", json);
187
+ return DomUtil.toXMLString(xml);
188
+ }
189
+
190
+ it("Should handle fixes made in version 1.1.3", () => {
191
+ expect(fromJSON({ $: "Hello" })).toBe("<root>Hello</root>");
192
+ expect(fromJSON({ "$delivery": "Hello" })).toBe("<root><delivery>Hello</delivery></root>");
193
+ expect(fromJSON({ "delivery": { $: "Hello" } })).toBe("<root><delivery>Hello</delivery></root>");
194
+ //expect(fromJSON({ "$delivery": "World", "delivery": { $: "Hello" } })).toBe("<root><delivery>Hello</delivery></root>");
195
+ expect(fromJSON({delivery: { "transaction": "0", "$": "0" }})).toBe('<root><delivery transaction="0">0</delivery></root>');
196
+ expect(fromJSON({delivery: { "$": "Hello", child: { name: "world" } }})).toBe('<root><delivery>Hello<child name="world"/></delivery></root>');
197
+ expect(fromJSON({delivery: { "$": "Hello", child: { name: "world" } }})).toBe('<root><delivery>Hello<child name="world"/></delivery></root>');
198
+ expect(fromJSON({ delivery: { $: "HelloWorld", child:{} } })).toBe('<root><delivery>HelloWorld<child/></delivery></root>');
199
+ });
178
200
  });
179
201
 
180
202
  describe('toJSON (SimpleJson)', function() {
@@ -185,20 +207,21 @@ describe('DomUtil', function() {
185
207
  return json;
186
208
  }
187
209
 
188
- assert.deepStrictEqual(toJSON('<root/>'), {});
189
- assert.deepStrictEqual(toJSON('<root a="1"/>'), { a:"1" });
190
- assert.deepStrictEqual(toJSON('<root a="1" b="2"/>'), { a:"1", b:"2" });
191
- assert.deepStrictEqual(toJSON('<root><a/></root>'), { a:{} });
192
- assert.deepStrictEqual(toJSON('<root><a/><a/></root>'), { a:[{},{}] });
210
+ it("Should convert XML to SimpleJSON", () => {
211
+ assert.deepStrictEqual(toJSON('<root/>'), {});
212
+ assert.deepStrictEqual(toJSON('<root a="1"/>'), { a:"1" });
213
+ assert.deepStrictEqual(toJSON('<root a="1" b="2"/>'), { a:"1", b:"2" });
214
+ assert.deepStrictEqual(toJSON('<root><a/></root>'), { a:{} });
215
+ assert.deepStrictEqual(toJSON('<root><a/><a/></root>'), { a:[{},{}] });
216
+ });
193
217
  });
194
218
 
195
219
  describe('fromJSON (invalid flavor)', function() {
196
- try {
197
- DomUtil.fromJSON("root", {}, "InvalidFlavor");
198
- assert.fail("Should have failed");
199
- } catch(ex) {
200
- assert.ok(true);
201
- }
220
+ it("Should fail", () => {
221
+ expect(() => {
222
+ DomUtil.fromJSON("root", {}, "InvalidFlavor");
223
+ }).toThrow();
224
+ });
202
225
  });
203
226
 
204
227
  describe('toJson (errors)', function() {
@@ -217,6 +240,233 @@ describe('DomUtil', function() {
217
240
 
218
241
  });
219
242
 
243
+ describe('toJson (SimpleJson, advanced)', function() {
244
+ function toJSON(xml) {
245
+ xml = DomUtil.parse(xml);
246
+ var json = DomUtil.toJSON(xml, "SimpleJson");
247
+ return json;
248
+ }
249
+
250
+ it("Should handle elements containing both text and other elements", () => {
251
+ expect(toJSON('<root>Hello</root>')).toEqual({ $: "Hello" });
252
+ expect(toJSON('<ctx><delivery>Hello</delivery></ctx>')).toEqual({ "$delivery": "Hello" });
253
+ expect(toJSON('<delivery transaction="0">0</delivery>')).toEqual({ "transaction": "0", "$": "0" });
254
+ expect(toJSON('<ctx><delivery transaction="0">0</delivery></ctx>')).toEqual({delivery: { "transaction": "0", "$": "0" }});
255
+ expect(toJSON('<ctx><delivery>Hello<child name="world"/></delivery></ctx>')).toEqual({delivery: { "$": "Hello", child: { name: "world" } }});
256
+ expect(toJSON('<ctx><delivery><child name="world"/>Hello</delivery></ctx>')).toEqual({delivery: { "$": "Hello", child: { name: "world" } }});
257
+ expect(toJSON('<root><delivery>Hello<child/>World</delivery></root>')).toEqual({ delivery: { $: "HelloWorld", child:{} } });
258
+ });
259
+
260
+ describe("Should handle insignificant whitespaces", () => {
261
+ it("Should not remove whitespace for element which does not have any children", () => {
262
+ expect(toJSON('<root><delivery> \nHello </delivery></root>')).toEqual({ $delivery: " \nHello " });
263
+ });
264
+ it("Should remove whitespace for root element even if it does not have any children. Because in SimpleJson we consider that root always has children", () => {
265
+ expect(toJSON('<root>\n</root>')).toEqual({ });
266
+ expect(toJSON('<root> \nHello </root>')).toEqual({ $: "Hello" });
267
+ expect(toJSON('<root> \nHello <delivery/></root>')).toEqual({ $: "Hello", delivery: {} });
268
+ expect(toJSON('<root> \nHello<delivery/> </root>')).toEqual({ $: "Hello", delivery: {} });
269
+ });
270
+ it("Should never remove whitespace in the middle of text", () => {
271
+ expect(toJSON('<root>Hello World</root>')).toEqual({ $: "Hello World" });
272
+ expect(toJSON('<root><delivery>Hello World</delivery></root>')).toEqual({ $delivery: "Hello World" });
273
+ expect(toJSON('<root><delivery> Hello World </delivery></root>')).toEqual({ $delivery: " Hello World " });
274
+ expect(toJSON('<root><delivery> Hello <child/>World </delivery></root>')).toEqual({ delivery: { $: "HelloWorld", child:{} } });
275
+ expect(toJSON('<root><delivery> Hello Cruel W<child/>orld </delivery></root>')).toEqual({ delivery: { $: "Hello Cruel World", child:{} } });
276
+ });
277
+
278
+ it("Should remove insignificant spaces", () => {
279
+ expect(toJSON('<ctx>\n <delivery>\n <target x="2"/>\n </delivery>\n</ctx>')).toEqual({delivery: { target: { x:"2"} }});
280
+ });
281
+
282
+ it("Should handle collections", () => {
283
+ expect(toJSON('<test-collection>\n <test a="1"></test>\n</test-collection>')).toEqual({test: [ { a:"1" }] });
284
+ expect(toJSON('<test-collection>\n <test a="1"></test>\n <test a="2"></test>\n</test-collection>')).toEqual({test: [ { a:"1" }, { a:"2" }] });
285
+ });
286
+
287
+ it("Should handle collections of text elements", () => {
288
+ expect(toJSON('<test-collection>\n <test>One</test>\n</test-collection>')).toEqual({test: [ { $:"One" }] });
289
+ expect(toJSON('<test-collection>\n <test>One</test>\n <test>Two</test>\n</test-collection>')).toEqual({test: [ { $:"One" }, { $:"Two" }] });
290
+ expect(toJSON('<array>\n <test>One</test>\n <test>Two</test>\n</array>')).toEqual({test: [ { $:"One" }, { $:"Two" }] });
291
+ });
292
+
293
+ it("Should never remove whitespaces of CDATA nodes", () => {
294
+ expect(toJSON('<root><![CDATA[]]></root>')).toEqual({});
295
+ expect(toJSON('<root><![CDATA[ Hello\tWorld\n ]]></root>')).toEqual({ $: " Hello\tWorld\n "});
296
+ expect(toJSON('<root><![CDATA[ Hello\t]]><![CDATA[World\n ]]></root>')).toEqual({ $: " Hello\tWorld\n "});
297
+ });
298
+
299
+ it("Should not handle whitespaces if element containing text has only attributes", () => {
300
+ // Whitespaces are always removed for the root node
301
+ expect(toJSON('<delivery transaction="0"> Hello World </delivery>')).toEqual({ "transaction": "0", "$": "Hello World" });
302
+ // But not for child nodes
303
+ expect(toJSON('<root><delivery transaction="0"> Hello World </delivery></root>')).toEqual({ delivery: { "transaction": "0", "$": " Hello World " } });
304
+ });
305
+ });
306
+
307
+ describe("Real payloads", () => {
308
+ it("Should convert report data payload", () => {
309
+ const xml = `<ctx lang="en" date="2022-11-18T08:04:06Z" _target="web" webApp-id="1583" _context="selection" _reportContext="deliverySending" _schema="nms:delivery" _hasFilter="false" _selection="12133" _folderModel="nmsDelivery" _folderLinkId="@folder-id" _folderLink="folder" activityHist="@r2rp0BOIZulQ3PcAaXVCr+9of9KxMPqM4MWmTTydhh4/qMVzTGmcRevNzHnoPS0WHvHKH084KIWom6NaVlzR1vCXv47bq3m/dfT3j7MQDSyDwb0rPU/4rD08CeDN3xqR6GazBmh+Lmz+ugo85WCwAaCDUYEJtG/EcqCOO0G+PRtjHlrNOhSrDSxanl4pxonQ4DhDTejA5VjSopu7pvV8U32e5k+fFuk/vvaOMHUP2Zk+VNuMnEytIExnbstFDepeSRDEMuIgmHWuENglhtcdfH3suIcibmqFyBF6Xupcqp2LlicJFFkXHXuM2LgUC7BTGsqMsN4HhNSs6NzW8ZhMPA==">
310
+ <userInfo datakitInDatabase="true" homeDir="" instanceLocale="en-US" locale="en-US" login="internal" loginCS="Internal account" loginId="0" noConsoleCnx="false" orgUnitId="0" theme="" timezone="Europe/Paris" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn:xtk:session" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
311
+ <timezone current="Europe/Paris" changed="false"/>
312
+ <_contextFilter>
313
+ <where>
314
+ <condition enabledIf="$(@_context) = 'selection' and $(@_hasFilter) = false" expr="@id = $noescaping(@_selection)"/>
315
+ <condition enabledIf="$(@_context) = 'selection' and $(@_hasFilter) and $(@_locationName) != 'descriptiveAnalysis'" expr="@id" setOperator="IN" subQuery="$(whereCond)"/>
316
+ </where>
317
+ </_contextFilter>
318
+ <activityHistory>
319
+ <activity name="page" type="page"/>
320
+ <activity name="query2" type="query"/>
321
+ <activity name="script2" type="script"/>
322
+ <activity name="query" type="query"/>
323
+ <activity name="start" type="start"/>
324
+ </activityHistory>
325
+ <data>
326
+ <query>
327
+ <delivery amount="0" article="0" contactDate="" error="0" estimatedRecipientOpen="0" estimatedTotalRecipientOpen="0" forward="0" label="" mirrorPage="0" newQuarantine="0" optOut="0" personClick="0" recipientClick="0" reject="0" success="0" toDeliver="0" totalRecipientClick="0" totalTarget="0" totalWebPage="0" transaction="0">0</delivery>
328
+ </query>
329
+ </data>
330
+ <vars>
331
+ <operator>0</operator>
332
+ </vars>
333
+ <title>Delivery:</title>
334
+ <query2/>
335
+ <chart_page_123722795831>
336
+ <data>&lt;data/&gt;</data>
337
+ <config>&lt;graphConfig accumulate="false" autoScale="true" autoStretch="true" computePercent="false" displayEmptySamples="false" filledOpacity="50" innerPieRadius="0" perspective="true" renderType="pie" reverseSeries="false" reverseStacking="false" showLabels="0" sortMode="2" zoomOnWheel="true"&gt;&lt;onclick action="url" enabledWhenHistory="false" target="_blank"/&gt;&lt;legend layout="right" visible="true"/&gt;&lt;series aggregate="sum" label="" renderGroup="layered" xpath="/dlvExclusion" xpathIndex="@label" xpathValue="@count"/&gt;&lt;/graphConfig&gt;</config>
338
+ </chart_page_123722795831>
339
+ </ctx>`;
340
+ expect(toJSON(xml)).toEqual(
341
+ {
342
+ userInfo: {
343
+ datakitInDatabase: "true",
344
+ homeDir: "",
345
+ instanceLocale: "en-US",
346
+ locale: "en-US",
347
+ login: "internal",
348
+ loginCS: "Internal account",
349
+ loginId: "0",
350
+ noConsoleCnx: "false",
351
+ orgUnitId: "0",
352
+ theme: "",
353
+ timezone: "Europe/Paris",
354
+ "xmlns:SOAP-ENV": "http://schemas.xmlsoap.org/soap/envelope/",
355
+ "xmlns:ns": "urn:xtk:session",
356
+ "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
357
+ "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
358
+ },
359
+ timezone: {
360
+ current: "Europe/Paris",
361
+ changed: "false",
362
+ },
363
+ _contextFilter: {
364
+ where: {
365
+ condition: [
366
+ {
367
+ enabledIf: "$(@_context) = 'selection' and $(@_hasFilter) = false",
368
+ expr: "@id = $noescaping(@_selection)",
369
+ },
370
+ {
371
+ enabledIf: "$(@_context) = 'selection' and $(@_hasFilter) and $(@_locationName) != 'descriptiveAnalysis'",
372
+ expr: "@id",
373
+ setOperator: "IN",
374
+ subQuery: "$(whereCond)",
375
+ },
376
+ ],
377
+ },
378
+ },
379
+ activityHistory: {
380
+ activity: [
381
+ {
382
+ name: "page",
383
+ type: "page",
384
+ },
385
+ {
386
+ name: "query2",
387
+ type: "query",
388
+ },
389
+ {
390
+ name: "script2",
391
+ type: "script",
392
+ },
393
+ {
394
+ name: "query",
395
+ type: "query",
396
+ },
397
+ {
398
+ name: "start",
399
+ type: "start",
400
+ },
401
+ ],
402
+ },
403
+ data: {
404
+ query: {
405
+ delivery: {
406
+ $: "0",
407
+ amount: "0",
408
+ article: "0",
409
+ contactDate: "",
410
+ error: "0",
411
+ estimatedRecipientOpen: "0",
412
+ estimatedTotalRecipientOpen: "0",
413
+ forward: "0",
414
+ label: "",
415
+ mirrorPage: "0",
416
+ newQuarantine: "0",
417
+ optOut: "0",
418
+ personClick: "0",
419
+ recipientClick: "0",
420
+ reject: "0",
421
+ success: "0",
422
+ toDeliver: "0",
423
+ totalRecipientClick: "0",
424
+ totalTarget: "0",
425
+ totalWebPage: "0",
426
+ transaction: "0",
427
+ },
428
+ },
429
+ },
430
+ vars: {
431
+ $operator: "0",
432
+ },
433
+ $title: "Delivery:",
434
+ query2: {
435
+ },
436
+ chart_page_123722795831: {
437
+ $data: "<data/>",
438
+ $config: "<graphConfig accumulate=\"false\" autoScale=\"true\" autoStretch=\"true\" computePercent=\"false\" displayEmptySamples=\"false\" filledOpacity=\"50\" innerPieRadius=\"0\" perspective=\"true\" renderType=\"pie\" reverseSeries=\"false\" reverseStacking=\"false\" showLabels=\"0\" sortMode=\"2\" zoomOnWheel=\"true\"><onclick action=\"url\" enabledWhenHistory=\"false\" target=\"_blank\"/><legend layout=\"right\" visible=\"true\"/><series aggregate=\"sum\" label=\"\" renderGroup=\"layered\" xpath=\"/dlvExclusion\" xpathIndex=\"@label\" xpathValue=\"@count\"/></graphConfig>",
439
+ },
440
+ lang: "en",
441
+ date: "2022-11-18T08:04:06Z",
442
+ _target: "web",
443
+ "webApp-id": "1583",
444
+ _context: "selection",
445
+ _reportContext: "deliverySending",
446
+ _schema: "nms:delivery",
447
+ _hasFilter: "false",
448
+ _selection: "12133",
449
+ _folderModel: "nmsDelivery",
450
+ _folderLinkId: "@folder-id",
451
+ _folderLink: "folder",
452
+ activityHist: "@r2rp0BOIZulQ3PcAaXVCr+9of9KxMPqM4MWmTTydhh4/qMVzTGmcRevNzHnoPS0WHvHKH084KIWom6NaVlzR1vCXv47bq3m/dfT3j7MQDSyDwb0rPU/4rD08CeDN3xqR6GazBmh+Lmz+ugo85WCwAaCDUYEJtG/EcqCOO0G+PRtjHlrNOhSrDSxanl4pxonQ4DhDTejA5VjSopu7pvV8U32e5k+fFuk/vvaOMHUP2Zk+VNuMnEytIExnbstFDepeSRDEMuIgmHWuENglhtcdfH3suIcibmqFyBF6Xupcqp2LlicJFFkXHXuM2LgUC7BTGsqMsN4HhNSs6NzW8ZhMPA==",
453
+ }
454
+ );
455
+ });
456
+ });
457
+
458
+ it("Should support attribute and element with same name", () => {
459
+ expect(toJSON('<ctx lang="en" timezone="Europe/Paris"><timezone current="Europe/Paris" changed="false"/></ctx>')).toEqual({
460
+ lang: "en",
461
+ "@timezone": "Europe/Paris",
462
+ "timezone": {
463
+ current: "Europe/Paris",
464
+ changed: "false",
465
+ }
466
+ });
467
+ });
468
+
469
+ });
220
470
 
221
471
  describe('toXMLString', function() {
222
472
 
@@ -46,9 +46,9 @@ describe('escaping', function() {
46
46
  });
47
47
  })
48
48
 
49
- describe('Tagged template litteral', function() {
49
+ describe('Tagged template literal', function() {
50
50
 
51
- it("Should escape in template litteral", () => {
51
+ it("Should escape in template literal", () => {
52
52
  expect(sdk.escapeXtk`Hello world`).toBe("Hello world");
53
53
  expect(sdk.escapeXtk`Hello 'world'`).toBe("Hello 'world'"); // only variables are escaped
54
54
 
@@ -77,7 +77,7 @@ describe('escaping', function() {
77
77
  expect(sdk.escapeXtk`@name=${"Rock 'n' Roll"}`).toBe("@name='Rock \\'n\\' Roll'");
78
78
  });
79
79
 
80
- describe('QueryDef & template litteral', () => {
80
+ describe('QueryDef & template literal', () => {
81
81
 
82
82
  })
83
83
 
package/test/util.test.js CHANGED
@@ -17,8 +17,8 @@ governing permissions and limitations under the License.
17
17
  *
18
18
  *********************************************************************************/
19
19
 
20
- const { Util, ArrayMap } = require('../src/util.js');
21
- const { SafeStorage, Cache } = require('../src/cache.js');
20
+ const { Util, ArrayMap } = require('../src/util.js');
21
+ const { SafeStorage, Cache } = require('../src/cache.js');
22
22
 
23
23
 
24
24
  describe('Util', function() {
@@ -102,7 +102,6 @@ describe('Util', function() {
102
102
  })
103
103
  })
104
104
 
105
-
106
105
  describe("Safe storage", () => {
107
106
  it("Should support undefined delegate", () => {
108
107
  const storage = new SafeStorage();