@adobe/acc-js-sdk 1.0.7 → 1.0.8

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.
@@ -23,6 +23,8 @@ const { DomException, XPath } = require('./domUtil.js');
23
23
  const XtkCaster = require('./xtkCaster.js').XtkCaster;
24
24
  const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
25
25
 
26
+ const PACKAGE_STATUS = { "never": 0, "always": 1, "default": 2, "preCreate": 3 };
27
+
26
28
  /**
27
29
  * @namespace Campaign
28
30
  */
@@ -30,7 +32,7 @@ const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
30
32
  // ========================================================================================
31
33
  // Helper functions
32
34
  // ========================================================================================
33
-
35
+
34
36
  // Determine if a name is an attribute name, i.e. if it starts with the "@" character
35
37
  const isAttributeName = function(name) { return name.length > 0 && name[0] == '@'; };
36
38
 
@@ -45,12 +47,42 @@ const isAttributeName = function(name) { return name.length > 0 && name[0] == '@
45
47
  * @see {@link XtkSchema}
46
48
  * @memberof Campaign
47
49
  */
48
- function newSchema(xml) {
50
+ function newSchema(xml, application) {
49
51
  if (xml.nodeType == 9) xml = xml.documentElement; // Document -> element
50
- var schema = new XtkSchema(xml);
52
+ var schema = new XtkSchema(application, xml);
51
53
  return schema;
52
54
  }
53
55
 
56
+ // Propagate implicit values
57
+ // Name -> Label -> Desc -> HelpText
58
+ function propagateImplicitValues(xtkDesc, labelOnly) {
59
+ if (!xtkDesc.label) {
60
+ if (xtkDesc.isAttribute) xtkDesc.label = xtkDesc.name.substring(1); // without @
61
+ else xtkDesc.label = xtkDesc.name;
62
+ // Force first letter as uppercase
63
+ xtkDesc.label = xtkDesc.label.substring(0, 1).toUpperCase() + xtkDesc.label.substring(1);
64
+ }
65
+ if (!labelOnly && !xtkDesc.description) xtkDesc.description = xtkDesc.label;
66
+ }
67
+
68
+ // ========================================================================================
69
+ // Schema Cache
70
+ // ========================================================================================
71
+ class SchemaCache {
72
+ constructor(client) {
73
+ this._client = client;
74
+ this._schemas = {};
75
+ }
76
+ async getSchema(schemaId) {
77
+ let schema = this._schemas[schemaId];
78
+ if (schema === undefined) {
79
+ schema = await this._client.application._getSchema(schemaId);
80
+ if (!schema) schema = null; // null = not found
81
+ this._schemas[schemaId] = schema;
82
+ }
83
+ return schema;
84
+ }
85
+ }
54
86
 
55
87
  // ========================================================================================
56
88
  // Keys
@@ -74,7 +106,7 @@ class XtkSchemaKey {
74
106
  this.name = EntityAccessor.getAttributeAsString(xml, "name");
75
107
  this.label = EntityAccessor.getAttributeAsString(xml, "label");
76
108
  this.description = EntityAccessor.getAttributeAsString(xml, "desc");
77
- this.isInternal = EntityAccessor.getAttributeAsString(xml, "internal");
109
+ this.isInternal = EntityAccessor.getAttributeAsBoolean(xml, "internal");
78
110
  this.allowEmptyPart = EntityAccessor.getAttributeAsString(xml, "allowEmptyPart");
79
111
  this.fields = {};
80
112
 
@@ -137,115 +169,345 @@ class XtkSchemaNode {
137
169
  * @type {XtkSchema}
138
170
  */
139
171
  this.schema = schema;
172
+
173
+ /**
174
+ * Returns a string of characters which provides the data policy of the current node.
175
+ * @type {string}
176
+ */
177
+ this.dataPolicy = EntityAccessor.getAttributeAsString(xml, "dataPolicy");
178
+
179
+ /**
180
+ * Returns a string of characters which specifies the editing type of the current node.
181
+ * @type {string}
182
+ */
183
+ this.editType = EntityAccessor.getAttributeAsString(xml, "editType");
184
+
185
+ /**
186
+ * Only on the root node, returns a string which contains the folder template(s). On the other nodes, it returns undefined.
187
+ * @type {string}
188
+ */
189
+ this.folderModel = EntityAccessor.getAttributeAsString(xml, "folderModel");
190
+
140
191
  /**
141
192
  * The parent node
142
193
  * @type {XtkSchemaNode}
143
194
  */
144
195
  this.parent = parentNode;
196
+
145
197
  /**
146
198
  * Indicates if the node is an attribute or not (element or schema itself)
147
199
  * @type {boolean}
148
200
  */
149
201
  this.isAttribute = isAttribute;
202
+
150
203
  /**
151
- * The attribute or the node name (without the "@" sign for attributes)
204
+ * The attribute or the node name (with the "@" sign for attributes)
152
205
  * @type {string}
153
206
  */
154
207
  this.name = (this.isAttribute ? "@" : "") + EntityAccessor.getAttributeAsString(xml, "name");
208
+
155
209
  /**
156
210
  * A human friendly name for the node. If the node is the schema node, the label will be in the plural form and "labelSingular"
157
211
  * should be used for the singular form
158
212
  * @type {string}
159
213
  */
160
214
  this.label = EntityAccessor.getAttributeAsString(xml, "label");
215
+
161
216
  /**
162
217
  * A long description of the node
163
218
  * @type {string}
164
219
  */
165
220
  this.description = EntityAccessor.getAttributeAsString(xml, "desc");
221
+
166
222
  /**
167
223
  * An optional image for the node
168
224
  * @type {string}
169
225
  */
170
226
  this.img = EntityAccessor.getAttributeAsString(xml, "img");
227
+ this.image = this.img;
228
+
229
+ /**
230
+ * Returns the name of the image of the current node in the form of a string of characters.
231
+ * @type {string}
232
+ */
233
+ this.enumerationImage = EntityAccessor.getAttributeAsString(xml, "enumImage");
234
+
171
235
  /**
172
236
  * The node type
173
237
  * @type {string}
174
238
  */
175
239
  this.type = EntityAccessor.getAttributeAsString(xml, "type");
240
+ if (!this.type && isAttribute) this.type = "string";
241
+
176
242
  /**
177
243
  * The node target
178
244
  * @type {string}
179
245
  */
180
- this.target = EntityAccessor.getAttributeAsString(xml, "target");
181
- /**
246
+ this.target = EntityAccessor.getAttributeAsString(xml, "target");
247
+
248
+ /**
182
249
  * The node integrity
183
250
  * @type {string}
184
251
  */
185
- this.integrity = EntityAccessor.getAttributeAsString(xml, "integrity");
186
- /**
252
+ this.integrity = EntityAccessor.getAttributeAsString(xml, "integrity");
253
+
254
+ /**
187
255
  * The node data length (applicable for string-types only)
188
256
  * @type {number}
189
257
  */
190
258
  this.length = EntityAccessor.getAttributeAsLong(xml, "length");
259
+ this.size = this.length;
260
+
191
261
  /**
192
262
  * The enum of the node
193
263
  * @type {string}
194
264
  */
195
- this.enum = EntityAccessor.getAttributeAsString(xml, "enum");
265
+ this.enum = EntityAccessor.getAttributeAsString(xml, "enum");
266
+
267
+ /**
268
+ * Returns a string of characters which is the name of the user enumeration used by the current node.
269
+ * @type {string}
270
+ */
271
+ this.userEnumeration = EntityAccessor.getAttributeAsString(xml, "userEnum");
272
+
273
+ /**
274
+ * Returns a boolean which indicates whether the value of the current node is linked to a user enumeration.
275
+ * @type {boolean}
276
+ */
277
+ this.hasUserEnumeration = !!this.userEnumeration;
278
+
196
279
  /**
197
280
  * "ref" attribute of the node, which references another node
198
281
  * @type {string}
199
282
  */
200
283
  this.ref = EntityAccessor.getAttributeAsString(xml, "ref");
201
-
202
284
  /**
203
285
  * Has an unlimited number of children of the same type
204
286
  * @type {boolean}
205
287
  */
206
288
  this.unbound = EntityAccessor.getAttributeAsBoolean(xml, "unbound");
289
+ this.isCollection = this.unbound;
290
+
291
+ /**
292
+ * is mapped as a xml
293
+ * @type {boolean}
294
+ */
295
+ this.isMappedAsXML = EntityAccessor.getAttributeAsBoolean(xml, "xml");
296
+ /**
297
+ * is an advanced node
298
+ * @type {boolean}
299
+ */
300
+ this.isAdvanced = EntityAccessor.getAttributeAsBoolean(xml, "advanced");
207
301
  /**
208
302
  * Children of the node. This is a object whose key are the names of the children nodes (without the "@"
209
303
  * character for attributes)
210
304
  * @type {Object.<string, Campaign.XtkSchemaNode>}
211
305
  */
212
- this.children = {};
306
+ this.children = {};
307
+
213
308
  /**
214
309
  * Count the children of a node
215
310
  * @type {number}
216
311
  */
217
312
  this.childrenCount = 0;
313
+
218
314
  /**
219
315
  * Indicates if the node is the root node, i.e. the first child node of the schema, whose name is the same as the schema name
220
316
  * @type {boolean}
221
317
  */
222
318
  this.isRoot = this.parent && !this.parent.parent && this.parent.name == this.name;
223
- /**
224
- * A user desciption of the node, in the form "label (name)"
225
- * @type {string}
226
- */
227
- this.userDescription = (this.label == "" || this.label == this.name) ? this.name : `${this.label} (${this.name})`;
319
+
228
320
  /**
229
321
  * Schema root elements may have a list of keys. This is a dictionary whose names are the key names and values the keys
230
322
  * @type {Object<string, XtkSchemaKey>}
231
323
  */
232
- this.keys = {};
324
+ this.keys = {};
325
+
233
326
  /**
234
327
  * The full path of the node
235
328
  * @type {string}
236
329
  */
237
330
  this.nodePath = this._getNodePath(true)._path;
331
+
238
332
  /**
239
333
  * Element of type "link" has an array of XtkJoin
240
- * @type {@type {XtkJoin[]}}
334
+ * @type {XtkJoin[]}
241
335
  */
242
336
  this.joins = [];
243
-
244
337
  for (var child of EntityAccessor.getChildElements(xml, "join")) {
245
338
  this.joins.push(new XtkJoin(child));
246
339
  }
247
340
 
248
- // Children (elements and attributes)
341
+ /**
342
+ * Returns a boolean which indicates whether the current node is ordinary.
343
+ * @type {boolean}
344
+ */
345
+ this.isAnyType = this.type === "ANY";
346
+
347
+ /**
348
+ * Returns a boolean which indicates whether the node is a link.
349
+ * @type {boolean}
350
+ */
351
+ this.isLink = this.type === "link";
352
+
353
+ /**
354
+ * Returns a boolean which indicates whether the value of the current node is linked to an enumeration.
355
+ * @type {boolean}
356
+ */
357
+ this.hasEnumeration = this.enum !== "";
358
+
359
+ /**
360
+ * Returns a boolean which indicates whether the current node is linked to an SQL table.
361
+ * @type {boolean}
362
+ */
363
+ this.hasSQLTable = this.sqlTable !== '';
364
+
365
+ /**
366
+ * The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
367
+ * @type {string}
368
+ */
369
+ this.SQLName = EntityAccessor.getAttributeAsString(xml, "sqlname");
370
+
371
+ /**
372
+ * The SQL name of the table. The property is an empty string if the object isn't the main element or if schema mapping isn't of SQL type.
373
+ * @type {string}
374
+ */
375
+ this.SQLTable = EntityAccessor.getAttributeAsString(xml, "sqltable");
376
+
377
+ /**
378
+ * Returns a boolean indicating whether the table is a temporary table. The table will not be created during database creation.
379
+ * @type {boolean}
380
+ */
381
+ this.isTemporaryTable = EntityAccessor.getAttributeAsBoolean(xml, "temporaryTable");
382
+
383
+ /**
384
+ * Returns a boolean which indicates whether the current node is a logical sub-division of the schema.
385
+ * @type {boolean}
386
+ */
387
+ // An element has no real value if its type is empty
388
+ this.isElementOnly = this.type === "";
389
+
390
+ /**
391
+ * Returns a boolean. If the value added is vrai, during record deduplication, the default value (defined in defaultValue) is automatically reapplied during recording.
392
+ * @type {boolean}
393
+ */
394
+ this.isDefaultOnDuplicate = EntityAccessor.getAttributeAsBoolean(xml, "defOnDuplicate");
395
+
396
+ /**
397
+ * True if the node is a link and if the join is external.
398
+ * @type {boolean}
399
+ */
400
+ this.isExternalJoin = EntityAccessor.getAttributeAsBoolean(xml, "externalJoin");
401
+
402
+ /**
403
+ * Returns a boolean which indicates whether the current node is mapped by a Memo.
404
+ * @type {boolean}
405
+ */
406
+ this.isMemo = this.type === "memo" || this.type === "CDATA";
407
+
408
+ /**
409
+ * Returns a boolean which indicates whether the current node is mapped by a MemoData.
410
+ * @type {boolean}
411
+ */
412
+ this.isMemoData = this.isMemo && this.name === 'data';
413
+
414
+ /**
415
+ * Returns a boolean which indicates whether the current node is a BLOB.
416
+ * @type {boolean}
417
+ */
418
+ this.isBlob = this.type === "blob";
419
+
420
+ /**
421
+ * Returns a boolean which indicates whether the current node is mapped from CDATA type XML.
422
+ * @type {boolean}
423
+ */
424
+ this.isCDATA = this.type === "CDATA";
425
+
426
+ /**
427
+ * Returns a boolean which indicates whether or not the current node can take the null value into account.
428
+ * @type {boolean}
429
+ */
430
+ const notNull = EntityAccessor.getAttributeAsString(xml, "notNull");
431
+ const sqlDefault = EntityAccessor.getAttributeAsString(xml, "sqlDefault");
432
+ const notNullOverriden = notNull || sqlDefault === "NULL"
433
+ this.isNotNull = notNullOverriden ? XtkCaster.asBoolean(notNull) : this.type === "int64" || this.type === "short" ||
434
+ this.type === "long" || this.type === "byte" || this.type === "float" || this.type === "double" ||
435
+ this.type === "money" || this.type === "percent" || this.type === "time" || this.type === "boolean";
436
+
437
+ /**
438
+ * Returns a boolean which indicates whether or not the value of the current node is mandatory.
439
+ * @type {boolean}
440
+ */
441
+ this.isRequired = EntityAccessor.getAttributeAsBoolean(xml, "required");
442
+
443
+ /**
444
+ * Returns a boolean which indicates whether the current node is mapped in SQL.
445
+ * @type {boolean}
446
+ */
447
+ this.isSQL = !!this.SQLName || !!this.SQLTable || (this.isLink && this.schema.mappingType === 'sql' && !this.isMappedAsXML);
448
+
449
+ /**
450
+ * The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
451
+ * @type {string}
452
+ */
453
+ this.PKSequence = EntityAccessor.getAttributeAsString(xml, "pkSequence");
454
+
455
+ /**
456
+ * Name of the reverse link in the target schema
457
+ * @type {string}
458
+ */
459
+ this.revLink = EntityAccessor.getAttributeAsString(xml, "revLink");
460
+
461
+ /**
462
+ * Returns a boolean which indicates whether the value of the current node is the result of a calculation.
463
+ * @type {boolean}
464
+ */
465
+ this.isCalculated = false;
466
+
467
+ /**
468
+ * Expression associated with the node
469
+ * @type {string}
470
+ */
471
+ this.expr = EntityAccessor.getAttributeAsString(xml, "expr");
472
+ if (this.expr) this.isCalculated = true;
473
+
474
+ /**
475
+ * Returns a boolean which indicates whether the value of the current node is incremented automatically.
476
+ * @type {boolean}
477
+ */
478
+ this.isAutoIncrement = EntityAccessor.getAttributeAsBoolean(xml, "autoIncrement");
479
+
480
+ /**
481
+ * Returns a boolean which indicates whether the current node is a primary key.
482
+ * @type {boolean}
483
+ */
484
+ this.isAutoPK = EntityAccessor.getAttributeAsBoolean(xml, "autopk");
485
+
486
+ /**
487
+ * Returns a boolean which indicates whether the current node is an automatic UUID
488
+ * @type {boolean}
489
+ */
490
+ this.isAutoUUID = EntityAccessor.getAttributeAsBoolean(xml, "autouuid");
491
+
492
+ /**
493
+ * Returns a boolean which indicates whether the schema is a staging schema
494
+ * @type {boolean}
495
+ */
496
+ this.isAutoStg = EntityAccessor.getAttributeAsBoolean(xml, "autoStg");
497
+
498
+ /**
499
+ * Returns a string that gives the package status.
500
+ * @type {"never" | "always" | "default" | "preCreate"}
501
+ */
502
+ this.packageStatusString = EntityAccessor.getAttributeAsString(xml, "pkgStatus");
503
+
504
+ /**
505
+ * Returns a number that gives the package status.
506
+ * @type {0 | 1 | 2 | 3}
507
+ */
508
+ this.packageStatus = PACKAGE_STATUS[this.packageStatusString];
509
+
510
+ // Children (elements and attributes)
249
511
  const childNodes = [];
250
512
  for (const child of EntityAccessor.getChildElements(xml, "attribute")) {
251
513
  const node = new XtkSchemaNode();
@@ -271,6 +533,10 @@ class XtkSchemaNode {
271
533
  const key = new XtkSchemaKey(schema, child, this);
272
534
  this.keys[key.name] = key;
273
535
  }
536
+
537
+ // Propagate implicit values
538
+ // Name -> Label -> Desc -> HelpText
539
+ propagateImplicitValues(this);
274
540
  }
275
541
 
276
542
  /**
@@ -279,7 +545,7 @@ class XtkSchemaNode {
279
545
  * @param {string} name the child name, without the "@" character for attributes
280
546
  * @returns {boolean} a boolean indicating whether the node contains a child with the given name
281
547
  */
282
- hasChild(name) {
548
+ hasChild(name) {
283
549
  var child = this.children[name];
284
550
  if (child) return true;
285
551
  // TODO: handle ref target
@@ -420,9 +686,9 @@ class XtkSchemaNode {
420
686
  */
421
687
  toString(indent) {
422
688
  indent = indent || "";
423
- var s = `${indent}${this.userDescription}\n`;
689
+ var s = `${indent}${this.label} (${this.name})\n`;
424
690
  for (var name in this.children) {
425
- s = s + this.children[name].toString(` ${indent}`);
691
+ s = s + this.children[name].toString(` ${indent}`);
426
692
  }
427
693
  return s;
428
694
  }
@@ -489,6 +755,8 @@ function XtkEnumerationValue(xml, baseType) {
489
755
  * @type {*}
490
756
  */
491
757
  this.value = XtkCaster.as(stringValue, baseType);
758
+
759
+ propagateImplicitValues(this, true);
492
760
  }
493
761
 
494
762
  /**
@@ -500,52 +768,57 @@ function XtkEnumerationValue(xml, baseType) {
500
768
  * @param {XML.XtkObject} xml the enumeration definition
501
769
  * @memberof Campaign
502
770
  */
503
- function XtkEnumeration(xml) {
504
- /**
505
- * The system enumeration name
506
- * @type {string}
507
- */
508
- this.name = EntityAccessor.getAttributeAsString(xml, "name");
509
- /**
510
- * A human friendly name for the system enumeration
511
- * @type {string}
512
- */
513
- this.label = EntityAccessor.getAttributeAsString(xml, "label");
514
- /**
515
- * A human friendly long description of the enumeration
516
- * @type {string}
517
- */
518
- this.description = EntityAccessor.getAttributeAsString(xml, "desc");
519
- /**
520
- * The type of the enumeration
521
- * @type {Campaign.XtkEnumerationType}
522
- */
523
- this.baseType = EntityAccessor.getAttributeAsString(xml, "basetype");
524
- /**
525
- * The default value of the enumeration
526
- * @type {Campaign.XtkEnumerationValue}
527
- */
528
- this.default = null;
529
- /**
530
- * Indicates if the enumeration has an image, i.e. if any of its values has an image
531
- * @type {boolean}
532
- */
533
- this.hasImage = false;
534
- /**
535
- * The enumerations values
536
- * @type {Object<string, Campaign.XtkEnumerationValue>}
537
- */
538
- this.values = {};
771
+ class XtkEnumeration {
772
+ constructor(schemaId, xml) {
773
+ /**
774
+ * The system enumeration name
775
+ * @type {string}
776
+ */
777
+ this.name = EntityAccessor.getAttributeAsString(xml, "name");
778
+
779
+ /**
780
+ * A human friendly name for the system enumeration
781
+ * @type {string}
782
+ */
783
+ this.label = EntityAccessor.getAttributeAsString(xml, "label");
784
+ /**
785
+ * A human friendly long description of the enumeration
786
+ * @type {string}
787
+ */
788
+ this.description = EntityAccessor.getAttributeAsString(xml, "desc");
789
+ /**
790
+ * The type of the enumeration
791
+ * @type {Campaign.XtkEnumerationType}
792
+ */
793
+ this.baseType = EntityAccessor.getAttributeAsString(xml, "basetype");
794
+ /**
795
+ * The default value of the enumeration
796
+ * @type {Campaign.XtkEnumerationValue}
797
+ */
798
+ this.default = null;
799
+ /**
800
+ * Indicates if the enumeration has an image, i.e. if any of its values has an image
801
+ * @type {boolean}
802
+ */
803
+ this.hasImage = false;
804
+ /**
805
+ * The enumerations values
806
+ * @type {Object<string, Campaign.XtkEnumerationValue>}
807
+ */
808
+ this.values = {};
539
809
 
540
- var defaultValue = EntityAccessor.getAttributeAsString(xml, "default");
810
+ var defaultValue = EntityAccessor.getAttributeAsString(xml, "default");
541
811
 
542
- for (var child of EntityAccessor.getChildElements(xml, "value")) {
543
- const e = new XtkEnumerationValue(child, this.baseType);
544
- this.values[e.name] = e;
545
- if (e.image != "") this.hasImage = true;
546
- const stringValue = EntityAccessor.getAttributeAsString(child, "value");
547
- if (defaultValue == stringValue)
548
- this.default = e;
812
+ for (var child of EntityAccessor.getChildElements(xml, "value")) {
813
+ const e = new XtkEnumerationValue(child, this.baseType);
814
+ this.values[e.name] = e;
815
+ if (e.image != "") this.hasImage = true;
816
+ const stringValue = EntityAccessor.getAttributeAsString(child, "value");
817
+ if (defaultValue == stringValue)
818
+ this.default = e;
819
+ }
820
+
821
+ propagateImplicitValues(this, true);
549
822
  }
550
823
  }
551
824
 
@@ -565,9 +838,9 @@ function XtkEnumeration(xml) {
565
838
  */
566
839
  class XtkSchema extends XtkSchemaNode {
567
840
 
568
- constructor(xml) {
841
+ constructor(application, xml) {
569
842
  super();
570
- this.init(this, xml);
843
+ this._application = application;
571
844
 
572
845
  /**
573
846
  * The namespace of the schema
@@ -578,6 +851,7 @@ class XtkSchema extends XtkSchemaNode {
578
851
  * The schema id, in the form "namespace:name"
579
852
  * @type {string}
580
853
  */
854
+ this.name = EntityAccessor.getAttributeAsString(xml, "name");
581
855
  this.id = `${this.namespace}:${this.name}`;
582
856
  /**
583
857
  * Indicates whether the schema is a library schema or not
@@ -594,29 +868,44 @@ class XtkSchema extends XtkSchemaNode {
594
868
  * @type {Campaign.XtkSchemaMappingType}
595
869
  */
596
870
  this.mappingType = EntityAccessor.getAttributeAsString(xml, "mappingType");
871
+ /**
872
+ * The MD5 code of the schema in the form of a hexadecimal string
873
+ * @type {string}
874
+ */
875
+ this.md5 = EntityAccessor.getAttributeAsString(xml, "md5");
597
876
  /**
598
877
  * The schema definition
599
878
  * @private
600
879
  * @type {XML.XtkObject}
601
880
  */
602
881
  this.xml = xml;
882
+
883
+ this.init(this, xml);
884
+
603
885
  /**
604
886
  * The schema root node, if it has one, i.e. the first child whose name matches the schema name
605
887
  * @type {Campaign.XtkSchemaNode}
606
888
  */
607
889
  this.root = this.children[this.name];
890
+
891
+ /**
892
+ * A user desciption of the node, in the form "label (name)"
893
+ * @type {string}
894
+ */
895
+ this.userDescription = (this.label == this.name) ? this.name : `${this.label} (${this.name})`;
896
+
608
897
  /**
609
898
  * Enumerations in this schema, as a dictionary whose keys are enumeration names and values are the
610
899
  * corresponding enumeration definitions
611
900
  * @type {Object<string, XtkEnumeration>}
612
901
  */
613
- this.enumerations = {};
902
+ this.enumerations = {};
614
903
 
615
- for (var child of EntityAccessor.getChildElements(xml, "enumeration")) {
616
- const e = new XtkEnumeration(child);
617
- this.enumerations[e.name] = e;
618
- }
619
- }
904
+ for (var child of EntityAccessor.getChildElements(xml, "enumeration")) {
905
+ const e = new XtkEnumeration(this.id, child);
906
+ this.enumerations[e.name] = e;
907
+ }
908
+ }
620
909
 
621
910
  /**
622
911
  * Creates a multi-line debug string representing the schema
@@ -625,7 +914,6 @@ class XtkSchema extends XtkSchemaNode {
625
914
  */
626
915
  toString() {
627
916
  var s = `${this.userDescription}\n`;
628
- //s = s + ` enumerations: [${enumerations}]`
629
917
  for (var name in this.children) {
630
918
  s = s + this.children[name].toString(" - ");
631
919
  }
@@ -680,8 +968,8 @@ class CurrentLogin {
680
968
  this._rightsSet = {};
681
969
  for (var child of EntityAccessor.getChildElements(userInfo, "login-right")) {
682
970
  const right = EntityAccessor.getAttributeAsString(child, "right");
683
- this.rights.push(right);
684
- this._rightsSet[right] = true;
971
+ this.rights.push(right);
972
+ this._rightsSet[right] = true;
685
973
  }
686
974
  }
687
975
 
@@ -729,6 +1017,7 @@ class Application {
729
1017
  */
730
1018
  constructor(client) {
731
1019
  this.client = client;
1020
+ this._schemaCache = new SchemaCache(client);
732
1021
  const info = this.client.getSessionInfo();
733
1022
  // When using "SessionToken" authentication, there is no actual logon, and therefore
734
1023
  // no "sessionInfo" object
@@ -738,25 +1027,25 @@ class Application {
738
1027
  * The server build number
739
1028
  * @type {string}
740
1029
  */
741
- this.buildNumber = EntityAccessor.getAttributeAsString(serverInfo, "buildNumber");
1030
+ this.buildNumber = EntityAccessor.getAttributeAsString(serverInfo, "buildNumber");
742
1031
  /**
743
1032
  * The Campaign instance name
744
1033
  * @type {string}
745
1034
  */
746
- this.instanceName = EntityAccessor.getAttributeAsString(serverInfo, "instanceName");
1035
+ this.instanceName = EntityAccessor.getAttributeAsString(serverInfo, "instanceName");
747
1036
  const userInfo = EntityAccessor.getElement(info, "userInfo");
748
1037
  /**
749
1038
  * The logged operator
750
1039
  * @type {Campaign.CurrentLogin}
751
1040
  */
752
- this.operator = new CurrentLogin(userInfo);
1041
+ this.operator = new CurrentLogin(userInfo);
753
1042
  /**
754
1043
  * The list of installed packages
755
1044
  * @type {string[]}
756
1045
  */
757
- this.packages = [];
1046
+ this.packages = [];
758
1047
  for (var p of EntityAccessor.getChildElements(userInfo, "installed-package")) {
759
- this.packages.push(`${EntityAccessor.getAttributeAsString(p, "namespace")}:${EntityAccessor.getAttributeAsString(p, "name")}`);
1048
+ this.packages.push(`${EntityAccessor.getAttributeAsString(p, "namespace")}:${EntityAccessor.getAttributeAsString(p, "name")}`);
760
1049
  }
761
1050
  }
762
1051
  }
@@ -769,10 +1058,15 @@ class Application {
769
1058
  * @returns {Campaign.XtkSchema} the schema, or null if the schema was not found
770
1059
  */
771
1060
  async getSchema(schemaId) {
1061
+ return this._schemaCache.getSchema(schemaId);
1062
+ }
1063
+
1064
+ // Private function: get a schema without using the cache
1065
+ async _getSchema(schemaId) {
772
1066
  const xml = await this.client.getSchema(schemaId, "xml");
773
1067
  if (!xml)
774
1068
  return null;
775
- return newSchema(xml);
1069
+ return newSchema(xml, this);
776
1070
  }
777
1071
 
778
1072
  /**
@@ -797,4 +1091,5 @@ exports.Application = Application;
797
1091
  // For tests
798
1092
  exports.newSchema = newSchema;
799
1093
  exports.newCurrentLogin = newCurrentLogin;
1094
+ exports.SchemaCache = SchemaCache;
800
1095
  })();