@adobe/acc-js-sdk 1.0.5 → 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/.github/workflows/codeql-analysis.yml +70 -0
- package/.vscode/launch.json +0 -1
- package/CHANGELOG.md +40 -0
- package/README.md +199 -63
- package/compile.js +3 -0
- package/package-lock.json +2175 -3383
- package/package.json +6 -7
- package/samples/002 - basics - schemas.js +3 -3
- package/samples/020 - encryption.js +5 -5
- package/src/application.js +427 -77
- package/src/cache.js +275 -0
- package/src/campaign.js +4 -0
- package/src/client.js +108 -30
- package/src/domUtil.js +6 -3
- package/src/entityAccessor.js +5 -5
- package/src/index.js +58 -2
- package/src/methodCache.js +21 -2
- package/src/optionCache.js +5 -1
- package/src/soap.js +46 -19
- package/src/testUtil.js +47 -0
- package/src/util.js +0 -229
- package/src/xtkCaster.js +80 -6
- package/src/xtkEntityCache.js +19 -3
- package/test/application.test.js +684 -616
- package/test/caches.test.js +148 -2
- package/test/client.test.js +341 -14
- package/test/crypto.test.js +16 -12
- 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 +59 -9
- package/test/soap.test.js +0 -6
- package/test/testUtil.test.js +64 -0
- package/test/util.test.js +2 -1
- package/test/xtkCaster.test.js +219 -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
|
|
|
@@ -88,6 +120,22 @@ class XtkSchemaKey {
|
|
|
88
120
|
|
|
89
121
|
}
|
|
90
122
|
|
|
123
|
+
/**
|
|
124
|
+
* A join in a XtkSchemaNode link type
|
|
125
|
+
*
|
|
126
|
+
* @private
|
|
127
|
+
* @class
|
|
128
|
+
* @constructor
|
|
129
|
+
* @param {} xml
|
|
130
|
+
* @memberof Campaign
|
|
131
|
+
*/
|
|
132
|
+
class XtkJoin {
|
|
133
|
+
|
|
134
|
+
constructor(xml) {
|
|
135
|
+
this.src = EntityAccessor.getAttributeAsString(xml, "xpath-src");
|
|
136
|
+
this.dst = EntityAccessor.getAttributeAsString(xml, "xpath-dst");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
91
139
|
// ========================================================================================
|
|
92
140
|
// Schema nodes
|
|
93
141
|
// ========================================================================================
|
|
@@ -121,85 +169,345 @@ class XtkSchemaNode {
|
|
|
121
169
|
* @type {XtkSchema}
|
|
122
170
|
*/
|
|
123
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
|
+
|
|
124
191
|
/**
|
|
125
192
|
* The parent node
|
|
126
193
|
* @type {XtkSchemaNode}
|
|
127
194
|
*/
|
|
128
195
|
this.parent = parentNode;
|
|
196
|
+
|
|
129
197
|
/**
|
|
130
198
|
* Indicates if the node is an attribute or not (element or schema itself)
|
|
131
199
|
* @type {boolean}
|
|
132
200
|
*/
|
|
133
201
|
this.isAttribute = isAttribute;
|
|
202
|
+
|
|
134
203
|
/**
|
|
135
|
-
* The attribute or the node name (
|
|
204
|
+
* The attribute or the node name (with the "@" sign for attributes)
|
|
136
205
|
* @type {string}
|
|
137
206
|
*/
|
|
138
207
|
this.name = (this.isAttribute ? "@" : "") + EntityAccessor.getAttributeAsString(xml, "name");
|
|
208
|
+
|
|
139
209
|
/**
|
|
140
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"
|
|
141
211
|
* should be used for the singular form
|
|
142
212
|
* @type {string}
|
|
143
213
|
*/
|
|
144
214
|
this.label = EntityAccessor.getAttributeAsString(xml, "label");
|
|
215
|
+
|
|
145
216
|
/**
|
|
146
217
|
* A long description of the node
|
|
147
218
|
* @type {string}
|
|
148
219
|
*/
|
|
149
220
|
this.description = EntityAccessor.getAttributeAsString(xml, "desc");
|
|
221
|
+
|
|
150
222
|
/**
|
|
151
223
|
* An optional image for the node
|
|
152
224
|
* @type {string}
|
|
153
225
|
*/
|
|
154
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
|
+
|
|
155
235
|
/**
|
|
156
236
|
* The node type
|
|
157
237
|
* @type {string}
|
|
158
238
|
*/
|
|
159
239
|
this.type = EntityAccessor.getAttributeAsString(xml, "type");
|
|
240
|
+
if (!this.type && isAttribute) this.type = "string";
|
|
241
|
+
|
|
160
242
|
/**
|
|
243
|
+
* The node target
|
|
244
|
+
* @type {string}
|
|
245
|
+
*/
|
|
246
|
+
this.target = EntityAccessor.getAttributeAsString(xml, "target");
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The node integrity
|
|
250
|
+
* @type {string}
|
|
251
|
+
*/
|
|
252
|
+
this.integrity = EntityAccessor.getAttributeAsString(xml, "integrity");
|
|
253
|
+
|
|
254
|
+
/**
|
|
161
255
|
* The node data length (applicable for string-types only)
|
|
162
256
|
* @type {number}
|
|
163
257
|
*/
|
|
164
258
|
this.length = EntityAccessor.getAttributeAsLong(xml, "length");
|
|
259
|
+
this.size = this.length;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The enum of the node
|
|
263
|
+
* @type {string}
|
|
264
|
+
*/
|
|
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
|
+
|
|
165
279
|
/**
|
|
166
280
|
* "ref" attribute of the node, which references another node
|
|
167
281
|
* @type {string}
|
|
168
282
|
*/
|
|
169
283
|
this.ref = EntityAccessor.getAttributeAsString(xml, "ref");
|
|
284
|
+
/**
|
|
285
|
+
* Has an unlimited number of children of the same type
|
|
286
|
+
* @type {boolean}
|
|
287
|
+
*/
|
|
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");
|
|
170
301
|
/**
|
|
171
302
|
* Children of the node. This is a object whose key are the names of the children nodes (without the "@"
|
|
172
303
|
* character for attributes)
|
|
173
304
|
* @type {Object.<string, Campaign.XtkSchemaNode>}
|
|
174
305
|
*/
|
|
175
|
-
|
|
306
|
+
this.children = {};
|
|
307
|
+
|
|
176
308
|
/**
|
|
177
309
|
* Count the children of a node
|
|
178
310
|
* @type {number}
|
|
179
311
|
*/
|
|
180
312
|
this.childrenCount = 0;
|
|
313
|
+
|
|
181
314
|
/**
|
|
182
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
|
|
183
316
|
* @type {boolean}
|
|
184
317
|
*/
|
|
185
318
|
this.isRoot = this.parent && !this.parent.parent && this.parent.name == this.name;
|
|
186
|
-
|
|
187
|
-
* A user desciption of the node, in the form "label (name)"
|
|
188
|
-
* @type {string}
|
|
189
|
-
*/
|
|
190
|
-
this.userDescription = (this.label == "" || this.label == this.name) ? this.name : `${this.label} (${this.name})`;
|
|
319
|
+
|
|
191
320
|
/**
|
|
192
321
|
* Schema root elements may have a list of keys. This is a dictionary whose names are the key names and values the keys
|
|
193
322
|
* @type {Object<string, XtkSchemaKey>}
|
|
194
323
|
*/
|
|
195
|
-
|
|
324
|
+
this.keys = {};
|
|
325
|
+
|
|
196
326
|
/**
|
|
197
327
|
* The full path of the node
|
|
198
328
|
* @type {string}
|
|
199
329
|
*/
|
|
200
330
|
this.nodePath = this._getNodePath(true)._path;
|
|
201
331
|
|
|
202
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Element of type "link" has an array of XtkJoin
|
|
334
|
+
* @type {XtkJoin[]}
|
|
335
|
+
*/
|
|
336
|
+
this.joins = [];
|
|
337
|
+
for (var child of EntityAccessor.getChildElements(xml, "join")) {
|
|
338
|
+
this.joins.push(new XtkJoin(child));
|
|
339
|
+
}
|
|
340
|
+
|
|
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)
|
|
203
511
|
const childNodes = [];
|
|
204
512
|
for (const child of EntityAccessor.getChildElements(xml, "attribute")) {
|
|
205
513
|
const node = new XtkSchemaNode();
|
|
@@ -225,6 +533,10 @@ class XtkSchemaNode {
|
|
|
225
533
|
const key = new XtkSchemaKey(schema, child, this);
|
|
226
534
|
this.keys[key.name] = key;
|
|
227
535
|
}
|
|
536
|
+
|
|
537
|
+
// Propagate implicit values
|
|
538
|
+
// Name -> Label -> Desc -> HelpText
|
|
539
|
+
propagateImplicitValues(this);
|
|
228
540
|
}
|
|
229
541
|
|
|
230
542
|
/**
|
|
@@ -233,7 +545,7 @@ class XtkSchemaNode {
|
|
|
233
545
|
* @param {string} name the child name, without the "@" character for attributes
|
|
234
546
|
* @returns {boolean} a boolean indicating whether the node contains a child with the given name
|
|
235
547
|
*/
|
|
236
|
-
|
|
548
|
+
hasChild(name) {
|
|
237
549
|
var child = this.children[name];
|
|
238
550
|
if (child) return true;
|
|
239
551
|
// TODO: handle ref target
|
|
@@ -242,6 +554,15 @@ class XtkSchemaNode {
|
|
|
242
554
|
return false;
|
|
243
555
|
}
|
|
244
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Indicates whether the current node has an unlimited number of children of the same type.
|
|
559
|
+
*
|
|
560
|
+
* @returns {boolean} a boolean indicating whether the node contains a child with the given name
|
|
561
|
+
*/
|
|
562
|
+
isUnbound() {
|
|
563
|
+
return this.unbound;
|
|
564
|
+
}
|
|
565
|
+
|
|
245
566
|
/**
|
|
246
567
|
* Computes the path of a node
|
|
247
568
|
*
|
|
@@ -365,9 +686,9 @@ class XtkSchemaNode {
|
|
|
365
686
|
*/
|
|
366
687
|
toString(indent) {
|
|
367
688
|
indent = indent || "";
|
|
368
|
-
var s = `${indent}${this.
|
|
689
|
+
var s = `${indent}${this.label} (${this.name})\n`;
|
|
369
690
|
for (var name in this.children) {
|
|
370
|
-
s = s + this.children[name].toString(`
|
|
691
|
+
s = s + this.children[name].toString(` ${indent}`);
|
|
371
692
|
}
|
|
372
693
|
return s;
|
|
373
694
|
}
|
|
@@ -434,6 +755,8 @@ function XtkEnumerationValue(xml, baseType) {
|
|
|
434
755
|
* @type {*}
|
|
435
756
|
*/
|
|
436
757
|
this.value = XtkCaster.as(stringValue, baseType);
|
|
758
|
+
|
|
759
|
+
propagateImplicitValues(this, true);
|
|
437
760
|
}
|
|
438
761
|
|
|
439
762
|
/**
|
|
@@ -445,52 +768,57 @@ function XtkEnumerationValue(xml, baseType) {
|
|
|
445
768
|
* @param {XML.XtkObject} xml the enumeration definition
|
|
446
769
|
* @memberof Campaign
|
|
447
770
|
*/
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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 = {};
|
|
484
809
|
|
|
485
|
-
|
|
810
|
+
var defaultValue = EntityAccessor.getAttributeAsString(xml, "default");
|
|
811
|
+
|
|
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
|
+
}
|
|
486
820
|
|
|
487
|
-
|
|
488
|
-
const e = new XtkEnumerationValue(child, this.baseType);
|
|
489
|
-
this.values[e.name] = e;
|
|
490
|
-
if (e.image != "") this.hasImage = true;
|
|
491
|
-
const stringValue = EntityAccessor.getAttributeAsString(child, "value");
|
|
492
|
-
if (defaultValue == stringValue)
|
|
493
|
-
this.default = e;
|
|
821
|
+
propagateImplicitValues(this, true);
|
|
494
822
|
}
|
|
495
823
|
}
|
|
496
824
|
|
|
@@ -510,9 +838,9 @@ function XtkEnumeration(xml) {
|
|
|
510
838
|
*/
|
|
511
839
|
class XtkSchema extends XtkSchemaNode {
|
|
512
840
|
|
|
513
|
-
constructor(xml) {
|
|
841
|
+
constructor(application, xml) {
|
|
514
842
|
super();
|
|
515
|
-
this.
|
|
843
|
+
this._application = application;
|
|
516
844
|
|
|
517
845
|
/**
|
|
518
846
|
* The namespace of the schema
|
|
@@ -523,6 +851,7 @@ class XtkSchema extends XtkSchemaNode {
|
|
|
523
851
|
* The schema id, in the form "namespace:name"
|
|
524
852
|
* @type {string}
|
|
525
853
|
*/
|
|
854
|
+
this.name = EntityAccessor.getAttributeAsString(xml, "name");
|
|
526
855
|
this.id = `${this.namespace}:${this.name}`;
|
|
527
856
|
/**
|
|
528
857
|
* Indicates whether the schema is a library schema or not
|
|
@@ -539,29 +868,44 @@ class XtkSchema extends XtkSchemaNode {
|
|
|
539
868
|
* @type {Campaign.XtkSchemaMappingType}
|
|
540
869
|
*/
|
|
541
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");
|
|
542
876
|
/**
|
|
543
877
|
* The schema definition
|
|
544
878
|
* @private
|
|
545
879
|
* @type {XML.XtkObject}
|
|
546
880
|
*/
|
|
547
881
|
this.xml = xml;
|
|
882
|
+
|
|
883
|
+
this.init(this, xml);
|
|
884
|
+
|
|
548
885
|
/**
|
|
549
886
|
* The schema root node, if it has one, i.e. the first child whose name matches the schema name
|
|
550
887
|
* @type {Campaign.XtkSchemaNode}
|
|
551
888
|
*/
|
|
552
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
|
+
|
|
553
897
|
/**
|
|
554
898
|
* Enumerations in this schema, as a dictionary whose keys are enumeration names and values are the
|
|
555
899
|
* corresponding enumeration definitions
|
|
556
900
|
* @type {Object<string, XtkEnumeration>}
|
|
557
901
|
*/
|
|
558
|
-
|
|
902
|
+
this.enumerations = {};
|
|
559
903
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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
|
+
}
|
|
565
909
|
|
|
566
910
|
/**
|
|
567
911
|
* Creates a multi-line debug string representing the schema
|
|
@@ -570,7 +914,6 @@ class XtkSchema extends XtkSchemaNode {
|
|
|
570
914
|
*/
|
|
571
915
|
toString() {
|
|
572
916
|
var s = `${this.userDescription}\n`;
|
|
573
|
-
//s = s + ` enumerations: [${enumerations}]`
|
|
574
917
|
for (var name in this.children) {
|
|
575
918
|
s = s + this.children[name].toString(" - ");
|
|
576
919
|
}
|
|
@@ -625,8 +968,8 @@ class CurrentLogin {
|
|
|
625
968
|
this._rightsSet = {};
|
|
626
969
|
for (var child of EntityAccessor.getChildElements(userInfo, "login-right")) {
|
|
627
970
|
const right = EntityAccessor.getAttributeAsString(child, "right");
|
|
628
|
-
|
|
629
|
-
|
|
971
|
+
this.rights.push(right);
|
|
972
|
+
this._rightsSet[right] = true;
|
|
630
973
|
}
|
|
631
974
|
}
|
|
632
975
|
|
|
@@ -674,6 +1017,7 @@ class Application {
|
|
|
674
1017
|
*/
|
|
675
1018
|
constructor(client) {
|
|
676
1019
|
this.client = client;
|
|
1020
|
+
this._schemaCache = new SchemaCache(client);
|
|
677
1021
|
const info = this.client.getSessionInfo();
|
|
678
1022
|
// When using "SessionToken" authentication, there is no actual logon, and therefore
|
|
679
1023
|
// no "sessionInfo" object
|
|
@@ -683,25 +1027,25 @@ class Application {
|
|
|
683
1027
|
* The server build number
|
|
684
1028
|
* @type {string}
|
|
685
1029
|
*/
|
|
686
|
-
|
|
1030
|
+
this.buildNumber = EntityAccessor.getAttributeAsString(serverInfo, "buildNumber");
|
|
687
1031
|
/**
|
|
688
1032
|
* The Campaign instance name
|
|
689
1033
|
* @type {string}
|
|
690
1034
|
*/
|
|
691
|
-
|
|
1035
|
+
this.instanceName = EntityAccessor.getAttributeAsString(serverInfo, "instanceName");
|
|
692
1036
|
const userInfo = EntityAccessor.getElement(info, "userInfo");
|
|
693
1037
|
/**
|
|
694
1038
|
* The logged operator
|
|
695
1039
|
* @type {Campaign.CurrentLogin}
|
|
696
1040
|
*/
|
|
697
|
-
|
|
1041
|
+
this.operator = new CurrentLogin(userInfo);
|
|
698
1042
|
/**
|
|
699
1043
|
* The list of installed packages
|
|
700
1044
|
* @type {string[]}
|
|
701
1045
|
*/
|
|
702
|
-
|
|
1046
|
+
this.packages = [];
|
|
703
1047
|
for (var p of EntityAccessor.getChildElements(userInfo, "installed-package")) {
|
|
704
|
-
|
|
1048
|
+
this.packages.push(`${EntityAccessor.getAttributeAsString(p, "namespace")}:${EntityAccessor.getAttributeAsString(p, "name")}`);
|
|
705
1049
|
}
|
|
706
1050
|
}
|
|
707
1051
|
}
|
|
@@ -714,10 +1058,15 @@ class Application {
|
|
|
714
1058
|
* @returns {Campaign.XtkSchema} the schema, or null if the schema was not found
|
|
715
1059
|
*/
|
|
716
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) {
|
|
717
1066
|
const xml = await this.client.getSchema(schemaId, "xml");
|
|
718
1067
|
if (!xml)
|
|
719
1068
|
return null;
|
|
720
|
-
return newSchema(xml);
|
|
1069
|
+
return newSchema(xml, this);
|
|
721
1070
|
}
|
|
722
1071
|
|
|
723
1072
|
/**
|
|
@@ -742,4 +1091,5 @@ exports.Application = Application;
|
|
|
742
1091
|
// For tests
|
|
743
1092
|
exports.newSchema = newSchema;
|
|
744
1093
|
exports.newCurrentLogin = newCurrentLogin;
|
|
1094
|
+
exports.SchemaCache = SchemaCache;
|
|
745
1095
|
})();
|