@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.
- package/CHANGELOG.md +22 -1
- package/README.md +178 -63
- package/compile.js +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/application.js +380 -85
- package/src/client.js +18 -10
- package/src/domUtil.js +6 -3
- package/src/entityAccessor.js +5 -5
- package/src/index.js +58 -2
- package/src/testUtil.js +47 -0
- package/src/xtkCaster.js +22 -0
- package/test/application.test.js +684 -655
- package/test/client.test.js +75 -4
- package/test/domUtil.test.js +150 -2
- package/test/escape.test.js +79 -47
- package/test/index.test.js +69 -1
- package/test/mock.js +11 -1
- package/test/testUtil.test.js +64 -0
- package/test/xtkCaster.test.js +122 -1
package/src/application.js
CHANGED
|
@@ -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.
|
|
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 (
|
|
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
|
-
|
|
181
|
-
|
|
246
|
+
this.target = EntityAccessor.getAttributeAsString(xml, "target");
|
|
247
|
+
|
|
248
|
+
/**
|
|
182
249
|
* The node integrity
|
|
183
250
|
* @type {string}
|
|
184
251
|
*/
|
|
185
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
689
|
+
var s = `${indent}${this.label} (${this.name})\n`;
|
|
424
690
|
for (var name in this.children) {
|
|
425
|
-
s = s + this.children[name].toString(`
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
-
|
|
810
|
+
var defaultValue = EntityAccessor.getAttributeAsString(xml, "default");
|
|
541
811
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
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.
|
|
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
|
-
|
|
902
|
+
this.enumerations = {};
|
|
614
903
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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
|
-
|
|
1030
|
+
this.buildNumber = EntityAccessor.getAttributeAsString(serverInfo, "buildNumber");
|
|
742
1031
|
/**
|
|
743
1032
|
* The Campaign instance name
|
|
744
1033
|
* @type {string}
|
|
745
1034
|
*/
|
|
746
|
-
|
|
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
|
-
|
|
1041
|
+
this.operator = new CurrentLogin(userInfo);
|
|
753
1042
|
/**
|
|
754
1043
|
* The list of installed packages
|
|
755
1044
|
* @type {string[]}
|
|
756
1045
|
*/
|
|
757
|
-
|
|
1046
|
+
this.packages = [];
|
|
758
1047
|
for (var p of EntityAccessor.getChildElements(userInfo, "installed-package")) {
|
|
759
|
-
|
|
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
|
})();
|