@adobe/acc-js-sdk 1.1.61 → 1.2.0
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/.cursor/commands/opsx-apply.md +152 -0
- package/.cursor/commands/opsx-archive.md +157 -0
- package/.cursor/commands/opsx-explore.md +173 -0
- package/.cursor/commands/opsx-propose.md +106 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
- package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
- package/.cursor/skills/openspec-explore/SKILL.md +288 -0
- package/.cursor/skills/openspec-propose/SKILL.md +110 -0
- package/.eslintrc.js +2 -2
- package/.github/prompts/opsx-apply.prompt.md +149 -0
- package/.github/prompts/opsx-archive.prompt.md +154 -0
- package/.github/prompts/opsx-explore.prompt.md +170 -0
- package/.github/prompts/opsx-propose.prompt.md +103 -0
- package/.github/skills/openspec-apply-change/SKILL.md +156 -0
- package/.github/skills/openspec-archive-change/SKILL.md +114 -0
- package/.github/skills/openspec-explore/SKILL.md +288 -0
- package/.github/skills/openspec-propose/SKILL.md +110 -0
- package/.github/workflows/codeql-analysis.yml +5 -4
- package/.github/workflows/npm-publish.yml +3 -3
- package/AGENTS.md +117 -0
- package/CLAUDE.md +2 -0
- package/MIGRATION.md +10 -0
- package/README.md +6 -2
- package/ai-docs/coding-rules.md +95 -0
- package/ai-docs/tech-stack.md +43 -0
- package/babel.config.js +5 -0
- package/docs/changeLog.html +34 -0
- package/docs/checkList.html +2 -2
- package/docs/connectionParameters.html +5 -0
- package/docs/quickstart.html +2 -1
- package/docs/release.html +1 -1
- package/openspec/config.yaml +20 -0
- package/package-lock.json +7437 -3924
- package/package.json +9 -7
- package/src/AGENTS.md +98 -0
- package/src/CLAUDE.md +2 -0
- package/src/application.js +637 -637
- package/src/cache.js +133 -133
- package/src/cacheRefresher.js +190 -190
- package/src/campaign.js +532 -532
- package/src/client.js +1539 -1532
- package/src/crypto.js +52 -52
- package/src/domUtil.js +346 -346
- package/src/entityAccessor.js +61 -61
- package/src/index.js +83 -83
- package/src/methodCache.js +69 -69
- package/src/optionCache.js +26 -26
- package/src/soap.js +321 -322
- package/src/testUtil.js +13 -13
- package/src/transport.js +70 -70
- package/src/util.js +147 -147
- package/src/web/bundler.js +5 -5
- package/src/xtkCaster.js +258 -258
- package/src/xtkEntityCache.js +34 -34
- package/src/xtkJob.js +185 -185
- package/test/AGENTS.md +37 -0
- package/test/CLAUDE.md +2 -0
- package/test/cacheRefresher.test.js +7 -0
- package/test/client.test.js +123 -81
- package/test/jest.config.js +6 -0
- package/test/observability.test.js +6 -1
- package/test/xtkJob.test.js +2 -2
package/src/application.js
CHANGED
|
@@ -10,31 +10,31 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
(function() {
|
|
13
|
-
"use strict";
|
|
13
|
+
"use strict";
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
/**********************************************************************************
|
|
16
|
+
/**********************************************************************************
|
|
17
17
|
*
|
|
18
18
|
* SDK "application" object
|
|
19
19
|
* https://docs.adobe.com/content/help/en/campaign-classic/technicalresources/api/c-Application.html
|
|
20
20
|
*
|
|
21
21
|
*********************************************************************************/
|
|
22
|
-
const { DomException, DomUtil, XPath } = require('./domUtil.js');
|
|
23
|
-
const XtkCaster = require('./xtkCaster.js').XtkCaster;
|
|
24
|
-
const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
|
|
25
|
-
const { ArrayMap } = require('./util.js');
|
|
22
|
+
const { DomException, DomUtil, XPath } = require('./domUtil.js');
|
|
23
|
+
const XtkCaster = require('./xtkCaster.js').XtkCaster;
|
|
24
|
+
const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
|
|
25
|
+
const { ArrayMap } = require('./util.js');
|
|
26
26
|
|
|
27
|
-
const PACKAGE_STATUS = { "never": 0, "always": 1, "default": 2, "preCreate": 3 };
|
|
27
|
+
const PACKAGE_STATUS = { "never": 0, "always": 1, "default": 2, "preCreate": 3 };
|
|
28
28
|
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
30
|
* @namespace Campaign
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
// ========================================================================================
|
|
34
|
-
// Helper functions
|
|
35
|
-
// ========================================================================================
|
|
33
|
+
// ========================================================================================
|
|
34
|
+
// Helper functions
|
|
35
|
+
// ========================================================================================
|
|
36
36
|
|
|
37
|
-
/**
|
|
37
|
+
/**
|
|
38
38
|
* Creates a schema object from an XML representation.
|
|
39
39
|
* The returned XtkSchema object will not be added to the application schema cache.
|
|
40
40
|
* If you do not pass an application object, it will not be possible to follow
|
|
@@ -47,32 +47,32 @@ const PACKAGE_STATUS = { "never": 0, "always": 1, "default": 2, "preCreate": 3 }
|
|
|
47
47
|
* @see {@link XtkSchema}
|
|
48
48
|
* @memberof Campaign
|
|
49
49
|
*/
|
|
50
|
-
|
|
50
|
+
function newSchema(xml, application) {
|
|
51
51
|
if (xml.nodeType == 9) xml = xml.documentElement; // Document -> element
|
|
52
52
|
var schema = new XtkSchema(application, xml);
|
|
53
53
|
return schema;
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
// Propagate implicit values
|
|
57
|
-
// Name -> Label -> Desc -> HelpText
|
|
58
|
-
function propagateImplicitValues(xtkDesc, labelOnly) {
|
|
56
|
+
// Propagate implicit values
|
|
57
|
+
// Name -> Label -> Desc -> HelpText
|
|
58
|
+
function propagateImplicitValues(xtkDesc, labelOnly) {
|
|
59
59
|
if (!xtkDesc.label) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
64
|
}
|
|
65
65
|
if (!labelOnly && !xtkDesc.description) {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
xtkDesc.description = xtkDesc.label;
|
|
67
|
+
xtkDesc.descriptionLocalizationId = xtkDesc.labelLocalizationId;
|
|
68
68
|
}
|
|
69
|
-
}
|
|
69
|
+
}
|
|
70
70
|
|
|
71
|
-
// ========================================================================================
|
|
72
|
-
// Schema Cache
|
|
73
|
-
// ========================================================================================
|
|
71
|
+
// ========================================================================================
|
|
72
|
+
// Schema Cache
|
|
73
|
+
// ========================================================================================
|
|
74
74
|
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
76
|
* A cache of schemas of type `XtkSchema` instead of plain XML or JSON objects
|
|
77
77
|
*
|
|
78
78
|
* @private
|
|
@@ -81,10 +81,10 @@ function propagateImplicitValues(xtkDesc, labelOnly) {
|
|
|
81
81
|
* @memberof Campaign
|
|
82
82
|
*/
|
|
83
83
|
|
|
84
|
-
class SchemaCache {
|
|
84
|
+
class SchemaCache {
|
|
85
85
|
constructor(client) {
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
this._client = client;
|
|
87
|
+
this._schemas = {};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
@@ -94,14 +94,14 @@ class SchemaCache {
|
|
|
94
94
|
* @returns {Campaign.XtkSchema} the schema, or null if the schema was not found
|
|
95
95
|
*/
|
|
96
96
|
async getSchema(schemaId) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
let schema = this._schemas[schemaId];
|
|
98
|
+
if (schema === undefined) {
|
|
99
|
+
schema = await this._client.application._getSchema(schemaId);
|
|
100
|
+
if (!schema) schema = null; // null = not found
|
|
101
|
+
if (!schemaId.startsWith("temp:group:"))
|
|
102
|
+
this._schemas[schemaId] = schema;
|
|
103
|
+
}
|
|
104
|
+
return schema;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
@@ -110,15 +110,15 @@ class SchemaCache {
|
|
|
110
110
|
* @param {string} schemaId
|
|
111
111
|
*/
|
|
112
112
|
invalidateCacheItem(schemaId) {
|
|
113
|
-
|
|
113
|
+
this._schemas[schemaId] = undefined;
|
|
114
114
|
}
|
|
115
|
-
}
|
|
115
|
+
}
|
|
116
116
|
|
|
117
|
-
// ========================================================================================
|
|
118
|
-
// Keys
|
|
119
|
-
// ========================================================================================
|
|
117
|
+
// ========================================================================================
|
|
118
|
+
// Keys
|
|
119
|
+
// ========================================================================================
|
|
120
120
|
|
|
121
|
-
/**
|
|
121
|
+
/**
|
|
122
122
|
* A key in a schema
|
|
123
123
|
*
|
|
124
124
|
* @private
|
|
@@ -129,69 +129,69 @@ class SchemaCache {
|
|
|
129
129
|
* @param {Campaign.XtkSchemaNode} schemaNode
|
|
130
130
|
* @memberof Campaign
|
|
131
131
|
*/
|
|
132
|
-
class XtkSchemaKey {
|
|
132
|
+
class XtkSchemaKey {
|
|
133
133
|
|
|
134
134
|
constructor(schema, xml, schemaNode) {
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
/**
|
|
137
137
|
* The schema this key belongs to
|
|
138
138
|
* @type {Campaign.XtkSchema}
|
|
139
139
|
*/
|
|
140
|
-
|
|
140
|
+
this.schema = schema;
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
/**
|
|
143
143
|
* The name of the key
|
|
144
144
|
* @type {string}
|
|
145
145
|
*/
|
|
146
|
-
|
|
146
|
+
this.name = EntityAccessor.getAttributeAsString(xml, "name");
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
/**
|
|
149
149
|
* A human friendly name for they key
|
|
150
150
|
* @type {string}
|
|
151
151
|
*/
|
|
152
|
-
|
|
152
|
+
this.label = EntityAccessor.getAttributeAsString(xml, "label");
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
/**
|
|
155
155
|
* A longer, human friendly description for they key
|
|
156
156
|
* @type {string}
|
|
157
157
|
*/
|
|
158
|
-
|
|
158
|
+
this.description = EntityAccessor.getAttributeAsString(xml, "desc");
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
/**
|
|
161
161
|
* Indicates if the key is internal or not
|
|
162
162
|
* @type {boolean}
|
|
163
163
|
*/
|
|
164
|
-
|
|
164
|
+
this.isInternal = EntityAccessor.getAttributeAsBoolean(xml, "internal");
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
/**
|
|
167
167
|
* Indicates if the fields (parts) of a composite key may be empty (null). At least one part must always be populated
|
|
168
168
|
* @type {boolean}
|
|
169
169
|
*/
|
|
170
|
-
|
|
170
|
+
this.allowEmptyPart = EntityAccessor.getAttributeAsString(xml, "allowEmptyPart");
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
/**
|
|
173
173
|
* The fields making up the key
|
|
174
174
|
* @type {Utils.ArrayMap<Campaign.XtkSchemaNode>}
|
|
175
175
|
*/
|
|
176
|
-
|
|
176
|
+
this.fields = new ArrayMap();
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
for (var child of EntityAccessor.getChildElements(xml, "keyfield")) {
|
|
179
|
+
const xpathString = EntityAccessor.getAttributeAsString(child, "xpath");
|
|
180
|
+
if (xpathString == "") throw new DomException(`Cannot create XtkSchemaKey for key '${this.name}': keyfield does not have an xpath attribute`);
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
182
|
+
// find key field
|
|
183
|
+
const xpath = new XPath(xpathString);
|
|
184
|
+
const elements = xpath.getElements();
|
|
185
|
+
let keyNode = schemaNode;
|
|
186
|
+
while (keyNode && elements.length > 0)
|
|
187
|
+
keyNode = keyNode.children[elements.shift()];
|
|
188
|
+
if (keyNode)
|
|
189
|
+
this.fields._push(xpathString, keyNode);
|
|
190
|
+
}
|
|
191
191
|
}
|
|
192
|
-
}
|
|
192
|
+
}
|
|
193
193
|
|
|
194
|
-
/**
|
|
194
|
+
/**
|
|
195
195
|
* A join in a XtkSchemaNode link type
|
|
196
196
|
*
|
|
197
197
|
* @private
|
|
@@ -200,29 +200,29 @@ class XtkSchemaKey {
|
|
|
200
200
|
* @param {} xml
|
|
201
201
|
* @memberof Campaign
|
|
202
202
|
*/
|
|
203
|
-
|
|
203
|
+
class XtkJoin {
|
|
204
204
|
|
|
205
205
|
constructor(xml) {
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
/**
|
|
208
208
|
* The xpath of the join condition on the source table
|
|
209
209
|
* @type {string}
|
|
210
210
|
*/
|
|
211
|
-
|
|
211
|
+
this.src = EntityAccessor.getAttributeAsString(xml, "xpath-src");
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
/**
|
|
214
214
|
* The xpath of the join condition on the destination table
|
|
215
215
|
* @type {string}
|
|
216
216
|
*/
|
|
217
|
-
|
|
217
|
+
this.dst = EntityAccessor.getAttributeAsString(xml, "xpath-dst");
|
|
218
218
|
}
|
|
219
|
-
}
|
|
219
|
+
}
|
|
220
220
|
|
|
221
|
-
// ========================================================================================
|
|
222
|
-
// Schema nodes
|
|
223
|
-
// ========================================================================================
|
|
221
|
+
// ========================================================================================
|
|
222
|
+
// Schema nodes
|
|
223
|
+
// ========================================================================================
|
|
224
224
|
|
|
225
|
-
/**
|
|
225
|
+
/**
|
|
226
226
|
* A Schema Node (CXtkNodeDef). Schemas are a hierarchy of nodes. The top-level node (i.e. the
|
|
227
227
|
* schema itself is also a node). The "root" node is the first child node having the same name
|
|
228
228
|
* as the schema itself
|
|
@@ -232,7 +232,7 @@ class XtkSchemaKey {
|
|
|
232
232
|
* @constructor
|
|
233
233
|
* @memberof Campaign
|
|
234
234
|
*/
|
|
235
|
-
class XtkSchemaNode {
|
|
235
|
+
class XtkSchemaNode {
|
|
236
236
|
|
|
237
237
|
constructor() {
|
|
238
238
|
}
|
|
@@ -246,460 +246,460 @@ class XtkSchemaNode {
|
|
|
246
246
|
*/
|
|
247
247
|
init(schema, xml, parentNode, isAttribute) {
|
|
248
248
|
|
|
249
|
-
|
|
249
|
+
/**
|
|
250
250
|
* The schema the node belongs to
|
|
251
251
|
* @type {XtkSchema}
|
|
252
252
|
*/
|
|
253
|
-
|
|
253
|
+
this.schema = schema;
|
|
254
254
|
|
|
255
|
-
|
|
255
|
+
/**
|
|
256
256
|
* Returns a string of characters which provides the data policy of the current node.
|
|
257
257
|
* @type {string}
|
|
258
258
|
*/
|
|
259
|
-
|
|
259
|
+
this.dataPolicy = EntityAccessor.getAttributeAsString(xml, "dataPolicy");
|
|
260
260
|
|
|
261
|
-
|
|
261
|
+
/**
|
|
262
262
|
* Returns a string of characters which provides the db enum of the current node.
|
|
263
263
|
* @type {string}
|
|
264
264
|
*/
|
|
265
|
-
|
|
265
|
+
this.dbEnum = EntityAccessor.getAttributeAsString(xml, "dbEnum");
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
/**
|
|
268
268
|
* Returns a string of characters which specifies the editing type of the current node.
|
|
269
269
|
* @type {string}
|
|
270
270
|
*/
|
|
271
|
-
|
|
271
|
+
this.editType = EntityAccessor.getAttributeAsString(xml, "edit");
|
|
272
272
|
|
|
273
|
-
|
|
273
|
+
/**
|
|
274
274
|
* Only on the root node, returns a string which contains the folder template(s). On the other nodes, it returns undefined.
|
|
275
275
|
* @type {string}
|
|
276
276
|
*/
|
|
277
|
-
|
|
277
|
+
this.folderModel = EntityAccessor.getAttributeAsString(xml, "folderModel");
|
|
278
278
|
|
|
279
|
-
|
|
279
|
+
/**
|
|
280
280
|
* The parent node
|
|
281
281
|
* @type {XtkSchemaNode}
|
|
282
282
|
*/
|
|
283
|
-
|
|
283
|
+
this.parent = parentNode;
|
|
284
284
|
|
|
285
|
-
|
|
285
|
+
/**
|
|
286
286
|
* Indicates if the node is an attribute or not (element or schema itself)
|
|
287
287
|
* @type {boolean}
|
|
288
288
|
*/
|
|
289
|
-
|
|
289
|
+
this.isAttribute = isAttribute;
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
/**
|
|
292
292
|
* The attribute or the node name (with the "@" sign for attributes)
|
|
293
293
|
* @type {string}
|
|
294
294
|
*/
|
|
295
|
-
|
|
295
|
+
this.name = (this.isAttribute ? "@" : "") + EntityAccessor.getAttributeAsString(xml, "name");
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
/**
|
|
298
298
|
* A human friendly name for the node. If the node is the schema node, the label will be in the plural form and "labelSingular"
|
|
299
299
|
* should be used for the singular form
|
|
300
300
|
* @type {string}
|
|
301
301
|
*/
|
|
302
|
-
|
|
302
|
+
this.label = EntityAccessor.getAttributeAsString(xml, "label");
|
|
303
303
|
|
|
304
|
-
|
|
304
|
+
/**
|
|
305
305
|
* A long description of the node
|
|
306
306
|
* @type {string}
|
|
307
307
|
*/
|
|
308
|
-
|
|
308
|
+
this.description = EntityAccessor.getAttributeAsString(xml, "desc");
|
|
309
309
|
|
|
310
|
-
|
|
310
|
+
/**
|
|
311
311
|
* An optional image for the node
|
|
312
312
|
* @type {string}
|
|
313
313
|
*/
|
|
314
|
-
|
|
314
|
+
this.img = EntityAccessor.getAttributeAsString(xml, "img");
|
|
315
315
|
|
|
316
|
-
|
|
316
|
+
/**
|
|
317
317
|
* An optional image for the node (alias to the img property)
|
|
318
318
|
* @type {string}
|
|
319
319
|
*/
|
|
320
|
-
|
|
320
|
+
this.image = this.img;
|
|
321
321
|
|
|
322
|
-
|
|
322
|
+
/**
|
|
323
323
|
* Returns the name of the image of the current node in the form of a string of characters.
|
|
324
324
|
* @type {string}
|
|
325
325
|
*/
|
|
326
|
-
|
|
326
|
+
this.enumerationImage = EntityAccessor.getAttributeAsString(xml, "enumImage");
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
/**
|
|
329
329
|
* The node type. Attribute nodes without an explicitedly defined type will be reported as "string"
|
|
330
330
|
* @type {string}
|
|
331
331
|
*/
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
this.type = EntityAccessor.getAttributeAsString(xml, "type");
|
|
333
|
+
if (!this.type && isAttribute) this.type = "string";
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
/**
|
|
336
336
|
* For link type nodes, the target of the link
|
|
337
337
|
* @type {string}
|
|
338
338
|
*/
|
|
339
|
-
|
|
339
|
+
this.target = EntityAccessor.getAttributeAsString(xml, "target");
|
|
340
340
|
|
|
341
|
-
|
|
341
|
+
/**
|
|
342
342
|
* The node integrity
|
|
343
343
|
* @type {string}
|
|
344
344
|
*/
|
|
345
|
-
|
|
345
|
+
this.integrity = EntityAccessor.getAttributeAsString(xml, "integrity");
|
|
346
346
|
|
|
347
|
-
|
|
347
|
+
/**
|
|
348
348
|
* The node data length (applicable for string-types only)
|
|
349
349
|
* @type {number}
|
|
350
350
|
*/
|
|
351
|
-
|
|
351
|
+
this.length = EntityAccessor.getAttributeAsLong(xml, "length");
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
/**
|
|
354
354
|
* The node data length (applicable for string-types only)
|
|
355
355
|
* @type {number}
|
|
356
356
|
*/
|
|
357
|
-
|
|
357
|
+
this.size = this.length;
|
|
358
358
|
|
|
359
|
-
|
|
359
|
+
/**
|
|
360
360
|
* The enum of the node
|
|
361
361
|
* @type {string}
|
|
362
362
|
*/
|
|
363
|
-
|
|
363
|
+
this.enum = EntityAccessor.getAttributeAsString(xml, "enum");
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
/**
|
|
366
366
|
* Returns a string of characters which is the name of the user enumeration used by the current node.
|
|
367
367
|
* @type {string}
|
|
368
368
|
*/
|
|
369
|
-
|
|
369
|
+
this.userEnumeration = EntityAccessor.getAttributeAsString(xml, "userEnum");
|
|
370
370
|
|
|
371
|
-
|
|
371
|
+
/**
|
|
372
372
|
* Returns a boolean which indicates whether the value of the current node is linked to a user enumeration.
|
|
373
373
|
* @type {boolean}
|
|
374
374
|
*/
|
|
375
|
-
|
|
375
|
+
this.hasUserEnumeration = !!this.userEnumeration;
|
|
376
376
|
|
|
377
|
-
|
|
377
|
+
/**
|
|
378
378
|
* "ref" attribute of the node, which references another node
|
|
379
379
|
* @type {string}
|
|
380
380
|
*/
|
|
381
|
-
|
|
381
|
+
this.ref = EntityAccessor.getAttributeAsString(xml, "ref");
|
|
382
382
|
|
|
383
|
-
|
|
383
|
+
/**
|
|
384
384
|
* Has an unlimited number of children of the same type
|
|
385
385
|
* @type {boolean}
|
|
386
386
|
*/
|
|
387
|
-
|
|
387
|
+
this.unbound = EntityAccessor.getAttributeAsBoolean(xml, "unbound");
|
|
388
388
|
|
|
389
|
-
|
|
389
|
+
/**
|
|
390
390
|
* If children are ordered
|
|
391
391
|
* @type {boolean}
|
|
392
392
|
*/
|
|
393
|
-
|
|
393
|
+
this.ordered = EntityAccessor.getAttributeAsBoolean(xml, "ordered");
|
|
394
394
|
|
|
395
|
-
|
|
395
|
+
/**
|
|
396
396
|
* The expression controlling the visibility of the current node
|
|
397
397
|
* @type {string}
|
|
398
398
|
*/
|
|
399
|
-
|
|
399
|
+
this.visibleIf = EntityAccessor.getAttributeAsString(xml, "visibleIf");
|
|
400
400
|
|
|
401
|
-
|
|
401
|
+
/**
|
|
402
402
|
* Has an unlimited number of children of the same type
|
|
403
403
|
* @type {boolean}
|
|
404
404
|
*/
|
|
405
|
-
|
|
405
|
+
this.isCollection = this.unbound;
|
|
406
406
|
|
|
407
|
-
|
|
407
|
+
/**
|
|
408
408
|
* is mapped as a xml
|
|
409
409
|
* @type {boolean}
|
|
410
410
|
*/
|
|
411
|
-
|
|
411
|
+
this.isMappedAsXML = EntityAccessor.getAttributeAsBoolean(xml, "xml");
|
|
412
412
|
|
|
413
|
-
|
|
413
|
+
/**
|
|
414
414
|
* is an advanced node
|
|
415
415
|
* @type {boolean}
|
|
416
416
|
*/
|
|
417
|
-
|
|
417
|
+
this.isAdvanced = EntityAccessor.getAttributeAsBoolean(xml, "advanced");
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
/**
|
|
420
420
|
* if returning the whole node when camparing difference
|
|
421
421
|
* @type {boolean}
|
|
422
422
|
*/
|
|
423
|
-
|
|
423
|
+
this.doesNotSupportDiff = EntityAccessor.getAttributeAsBoolean(xml, "doesNotSupportDiff");
|
|
424
424
|
|
|
425
|
-
|
|
425
|
+
/**
|
|
426
426
|
* Children of the node. This is a object whose key are the names of the children nodes (without the "@"
|
|
427
427
|
* character for attributes)
|
|
428
428
|
* @type {Utils.ArrayMap.<Campaign.XtkSchemaNode>}
|
|
429
429
|
*/
|
|
430
|
-
|
|
430
|
+
this.children = new ArrayMap();
|
|
431
431
|
|
|
432
|
-
|
|
432
|
+
/**
|
|
433
433
|
* Count the children of a node
|
|
434
434
|
* @type {number}
|
|
435
435
|
*/
|
|
436
|
-
|
|
436
|
+
this.childrenCount = 0;
|
|
437
437
|
|
|
438
|
-
|
|
438
|
+
/**
|
|
439
439
|
* Get the default value of a node
|
|
440
440
|
* @type {string}
|
|
441
441
|
*/
|
|
442
|
-
|
|
442
|
+
this.default = EntityAccessor.getAttributeAsString(xml, "default");
|
|
443
443
|
|
|
444
|
-
|
|
444
|
+
/**
|
|
445
445
|
* Get the default translation for the default value of a node
|
|
446
446
|
* @type {string}
|
|
447
447
|
*/
|
|
448
|
-
|
|
448
|
+
this.translatedDefault = EntityAccessor.getAttributeAsString(xml, "translatedDefault");
|
|
449
449
|
|
|
450
|
-
|
|
450
|
+
/**
|
|
451
451
|
* 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
|
|
452
452
|
* @type {boolean}
|
|
453
453
|
*/
|
|
454
|
-
|
|
454
|
+
this.isRoot = this.parent && !this.parent.parent && this.parent.name == this.name;
|
|
455
455
|
|
|
456
|
-
|
|
456
|
+
/**
|
|
457
457
|
* Schema root elements may have a list of keys. This is a dictionary whose names are the key names and values the keys
|
|
458
458
|
* @type {ArrayNode<Campaign.XtkSchemaKey>}
|
|
459
459
|
*/
|
|
460
|
-
|
|
460
|
+
this.keys = new ArrayMap();
|
|
461
461
|
|
|
462
|
-
|
|
462
|
+
/**
|
|
463
463
|
* The full path of the node
|
|
464
464
|
* @type {string}
|
|
465
465
|
*/
|
|
466
|
-
|
|
466
|
+
this.nodePath = this._getNodePath(true)._path;
|
|
467
467
|
|
|
468
|
-
|
|
468
|
+
this._buildLocalizationIds();
|
|
469
469
|
|
|
470
|
-
|
|
470
|
+
/**
|
|
471
471
|
* Element of type "link" has an array of XtkJoin
|
|
472
472
|
* @type {XtkJoin[]}
|
|
473
473
|
*/
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
474
|
+
this.joins = [];
|
|
475
|
+
for (var child of EntityAccessor.getChildElements(xml, "join")) {
|
|
476
|
+
this.joins.push(new XtkJoin(child));
|
|
477
|
+
}
|
|
478
478
|
|
|
479
|
-
|
|
479
|
+
/**
|
|
480
480
|
* Returns a boolean which indicates whether the current node is ordinary.
|
|
481
481
|
* @type {boolean}
|
|
482
482
|
*/
|
|
483
|
-
|
|
483
|
+
this.isAnyType = this.type === "ANY";
|
|
484
484
|
|
|
485
|
-
|
|
485
|
+
/**
|
|
486
486
|
* Returns a boolean which indicates whether the node is a link.
|
|
487
487
|
* @type {boolean}
|
|
488
488
|
*/
|
|
489
|
-
|
|
489
|
+
this.isLink = this.type === "link";
|
|
490
490
|
|
|
491
|
-
|
|
491
|
+
/**
|
|
492
492
|
* Returns a boolean which indicates whether the value of the current node is linked to an enumeration.
|
|
493
493
|
* @type {boolean}
|
|
494
494
|
*/
|
|
495
|
-
|
|
495
|
+
this.hasEnumeration = this.enum !== "";
|
|
496
496
|
|
|
497
|
-
|
|
497
|
+
/**
|
|
498
498
|
* Returns a boolean which indicates whether the current node is linked to an SQL table.
|
|
499
499
|
* @type {boolean}
|
|
500
500
|
*/
|
|
501
|
-
|
|
501
|
+
this.hasSQLTable = this.sqlTable !== '';
|
|
502
502
|
|
|
503
|
-
|
|
503
|
+
/**
|
|
504
504
|
* The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
|
|
505
505
|
* @type {string}
|
|
506
506
|
*/
|
|
507
|
-
|
|
507
|
+
this.SQLName = EntityAccessor.getAttributeAsString(xml, "sqlname");
|
|
508
508
|
|
|
509
|
-
|
|
509
|
+
/**
|
|
510
510
|
* 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.
|
|
511
511
|
* @type {string}
|
|
512
512
|
*/
|
|
513
|
-
|
|
513
|
+
this.SQLTable = EntityAccessor.getAttributeAsString(xml, "sqltable");
|
|
514
514
|
|
|
515
|
-
|
|
515
|
+
/**
|
|
516
516
|
* Returns a boolean indicating whether the table is a temporary table. The table will not be created during database creation.
|
|
517
517
|
* @type {boolean}
|
|
518
518
|
*/
|
|
519
|
-
|
|
519
|
+
this.isTemporaryTable = EntityAccessor.getAttributeAsBoolean(xml, "temporaryTable");
|
|
520
520
|
|
|
521
|
-
|
|
521
|
+
/**
|
|
522
522
|
* Returns a boolean which indicates whether the current node is a logical sub-division of the schema.
|
|
523
523
|
* @type {boolean}
|
|
524
524
|
*/
|
|
525
|
-
|
|
526
|
-
|
|
525
|
+
// An element has no real value if its type is empty
|
|
526
|
+
this.isElementOnly = this.type === "";
|
|
527
527
|
|
|
528
|
-
|
|
528
|
+
/**
|
|
529
529
|
* Returns a boolean. If the value added is vrai, during record deduplication, the default value (defined in defaultValue) is automatically reapplied during recording.
|
|
530
530
|
* @type {boolean}
|
|
531
531
|
*/
|
|
532
|
-
|
|
532
|
+
this.isDefaultOnDuplicate = EntityAccessor.getAttributeAsBoolean(xml, "defOnDuplicate");
|
|
533
533
|
|
|
534
|
-
|
|
534
|
+
/**
|
|
535
535
|
* True if the node is a link and if the join is external.
|
|
536
536
|
* @type {boolean}
|
|
537
537
|
*/
|
|
538
|
-
|
|
538
|
+
this.isExternalJoin = EntityAccessor.getAttributeAsBoolean(xml, "externalJoin");
|
|
539
539
|
|
|
540
|
-
|
|
540
|
+
/**
|
|
541
541
|
* Returns a boolean which indicates whether the current node is mapped by a Memo.
|
|
542
542
|
* @type {boolean}
|
|
543
543
|
*/
|
|
544
|
-
|
|
544
|
+
this.isMemo = this.type === "memo" || this.type === "CDATA";
|
|
545
545
|
|
|
546
|
-
|
|
546
|
+
/**
|
|
547
547
|
* Returns a boolean which indicates whether the current node is mapped by a MemoData.
|
|
548
548
|
* @type {boolean}
|
|
549
549
|
*/
|
|
550
|
-
|
|
550
|
+
this.isMemoData = this.isMemo && this.name === 'data';
|
|
551
551
|
|
|
552
|
-
|
|
552
|
+
/**
|
|
553
553
|
* Returns a boolean which indicates whether the current node is a BLOB.
|
|
554
554
|
* @type {boolean}
|
|
555
555
|
*/
|
|
556
|
-
|
|
556
|
+
this.isBlob = this.type === "blob";
|
|
557
557
|
|
|
558
|
-
|
|
558
|
+
/**
|
|
559
559
|
* Returns a boolean which indicates whether the current node is mapped from CDATA type XML.
|
|
560
560
|
* @type {boolean}
|
|
561
561
|
*/
|
|
562
|
-
|
|
562
|
+
this.isCDATA = this.type === "CDATA";
|
|
563
563
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
564
|
+
const notNull = EntityAccessor.getAttributeAsString(xml, "notNull");
|
|
565
|
+
const sqlDefault = EntityAccessor.getAttributeAsString(xml, "sqlDefault");
|
|
566
|
+
const notNullOverriden = notNull || sqlDefault === "NULL";
|
|
567
|
+
/**
|
|
568
568
|
* Returns a boolean which indicates whether or not the current node can take the null value into account.
|
|
569
569
|
* @type {boolean}
|
|
570
570
|
*/
|
|
571
|
-
|
|
571
|
+
this.isNotNull = notNullOverriden ? XtkCaster.asBoolean(notNull) : this.type === "int64" || this.type === "short" ||
|
|
572
572
|
this.type === "long" || this.type === "byte" || this.type === "float" || this.type === "double" ||
|
|
573
573
|
this.type === "money" || this.type === "percent" || this.type === "time" || this.type === "boolean";
|
|
574
574
|
|
|
575
|
-
|
|
575
|
+
/**
|
|
576
576
|
* Returns a boolean which indicates whether or not the value of the current node is mandatory.
|
|
577
577
|
* @type {boolean}
|
|
578
578
|
*/
|
|
579
|
-
|
|
579
|
+
this.isRequired = EntityAccessor.getAttributeAsBoolean(xml, "required");
|
|
580
580
|
|
|
581
|
-
|
|
581
|
+
/**
|
|
582
582
|
* Returns a boolean which indicates whether the current node is mapped in SQL.
|
|
583
583
|
* @type {boolean}
|
|
584
584
|
*/
|
|
585
|
-
|
|
585
|
+
this.isSQL = !!this.SQLName || !!this.SQLTable || (this.isLink && this.schema.mappingType === 'sql' && !this.isMappedAsXML);
|
|
586
586
|
|
|
587
|
-
|
|
587
|
+
/**
|
|
588
588
|
* The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
|
|
589
589
|
* @type {string}
|
|
590
590
|
*/
|
|
591
|
-
|
|
591
|
+
this.PKSequence = EntityAccessor.getAttributeAsString(xml, "pkSequence");
|
|
592
592
|
|
|
593
|
-
|
|
593
|
+
/**
|
|
594
594
|
* Name of the reverse link in the target schema
|
|
595
595
|
* @type {string}
|
|
596
596
|
*/
|
|
597
|
-
|
|
597
|
+
this.revLink = EntityAccessor.getAttributeAsString(xml, "revLink");
|
|
598
598
|
|
|
599
|
-
|
|
599
|
+
/**
|
|
600
600
|
* Returns a boolean which indicates whether the value of the current node is the result of a calculation.
|
|
601
601
|
* @type {boolean}
|
|
602
602
|
*/
|
|
603
|
-
|
|
603
|
+
this.isCalculated = false;
|
|
604
604
|
|
|
605
|
-
|
|
605
|
+
/**
|
|
606
606
|
* Expression associated with the node
|
|
607
607
|
* @type {string}
|
|
608
608
|
*/
|
|
609
|
-
|
|
610
|
-
|
|
609
|
+
this.expr = EntityAccessor.getAttributeAsString(xml, "expr");
|
|
610
|
+
if (this.expr) this.isCalculated = true;
|
|
611
611
|
|
|
612
|
-
|
|
612
|
+
/**
|
|
613
613
|
* Returns a boolean which indicates whether the value of the current node is incremented automatically.
|
|
614
614
|
* @type {boolean}
|
|
615
615
|
*/
|
|
616
|
-
|
|
616
|
+
this.isAutoIncrement = EntityAccessor.getAttributeAsBoolean(xml, "autoIncrement");
|
|
617
617
|
|
|
618
|
-
|
|
618
|
+
/**
|
|
619
619
|
* Returns a boolean which indicates whether the current node is a primary key.
|
|
620
620
|
* @type {boolean}
|
|
621
621
|
*/
|
|
622
|
-
|
|
622
|
+
this.isAutoPK = EntityAccessor.getAttributeAsBoolean(xml, "autopk");
|
|
623
623
|
|
|
624
|
-
|
|
624
|
+
/**
|
|
625
625
|
* Returns a boolean which indicates whether the current node is an automatic UUID
|
|
626
626
|
* @type {boolean}
|
|
627
627
|
*/
|
|
628
|
-
|
|
628
|
+
this.isAutoUUID = EntityAccessor.getAttributeAsBoolean(xml, "autouuid");
|
|
629
629
|
|
|
630
|
-
|
|
630
|
+
/**
|
|
631
631
|
* Returns a boolean which indicates whether the schema is a staging schema
|
|
632
632
|
* @type {boolean}
|
|
633
633
|
*/
|
|
634
|
-
|
|
634
|
+
this.isAutoStg = EntityAccessor.getAttributeAsBoolean(xml, "autoStg");
|
|
635
635
|
|
|
636
|
-
|
|
636
|
+
/**
|
|
637
637
|
* Returns a string that gives the package status.
|
|
638
638
|
* @type {"never" | "always" | "default" | "preCreate"}
|
|
639
639
|
*/
|
|
640
|
-
|
|
640
|
+
this.packageStatusString = EntityAccessor.getAttributeAsString(xml, "pkgStatus");
|
|
641
641
|
|
|
642
|
-
|
|
642
|
+
/**
|
|
643
643
|
* Returns a number that gives the package status.
|
|
644
644
|
* @type {0 | 1 | 2 | 3}
|
|
645
645
|
*/
|
|
646
|
-
|
|
646
|
+
this.packageStatus = PACKAGE_STATUS[this.packageStatusString];
|
|
647
647
|
|
|
648
|
-
|
|
648
|
+
/**
|
|
649
649
|
* Returns a string (a schema id) which indicates the custom/extended entity, attribute belongs to.
|
|
650
650
|
*/
|
|
651
|
-
|
|
651
|
+
this.belongsTo = EntityAccessor.getAttributeAsString(xml, "belongsTo");
|
|
652
652
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
if (child.tagName === "element") {
|
|
662
|
-
const node = new XtkSchemaNode();
|
|
663
|
-
node.init(schema, child, this, false);
|
|
664
|
-
childNodes.push(node);
|
|
665
|
-
}
|
|
666
|
-
if (child.tagName === "compute-string") {
|
|
667
|
-
this.expr = EntityAccessor.getAttributeAsString(child, "expr");
|
|
668
|
-
this.isCalculated = false;
|
|
669
|
-
}
|
|
670
|
-
if (child.tagName === "default" || child.tagName === "translatedDefault") {
|
|
671
|
-
if(this.unbound) {
|
|
672
|
-
// Default value for a collection of elements
|
|
673
|
-
const xml = DomUtil.parse(`<xml>${child.textContent}</xml>`);
|
|
674
|
-
const json = DomUtil.toJSON(xml);
|
|
675
|
-
if(child.tagName === "translatedDefault") {
|
|
676
|
-
this.translatedDefault = XtkCaster.asArray(json[this.name]);
|
|
677
|
-
} else {
|
|
678
|
-
this.default = XtkCaster.asArray(json[this.name]);
|
|
679
|
-
}
|
|
680
|
-
} else {
|
|
681
|
-
if(child.tagName === "translatedDefault") {
|
|
682
|
-
this.translatedDefault = child.textContent;
|
|
683
|
-
} else {
|
|
684
|
-
this.default = child.textContent;
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
653
|
+
// Children (elements and attributes)
|
|
654
|
+
const childNodes = [];
|
|
655
|
+
for (const child of EntityAccessor.getChildElements(xml)) {
|
|
656
|
+
if (child.tagName === "attribute") {
|
|
657
|
+
const node = new XtkSchemaNode();
|
|
658
|
+
node.init(schema, child, this, true);
|
|
659
|
+
childNodes.push(node);
|
|
688
660
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
661
|
+
if (child.tagName === "element") {
|
|
662
|
+
const node = new XtkSchemaNode();
|
|
663
|
+
node.init(schema, child, this, false);
|
|
664
|
+
childNodes.push(node);
|
|
692
665
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const key = new XtkSchemaKey(schema, child, this);
|
|
697
|
-
this.keys._push(key.name, key);
|
|
666
|
+
if (child.tagName === "compute-string") {
|
|
667
|
+
this.expr = EntityAccessor.getAttributeAsString(child, "expr");
|
|
668
|
+
this.isCalculated = false;
|
|
698
669
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
670
|
+
if (child.tagName === "default" || child.tagName === "translatedDefault") {
|
|
671
|
+
if(this.unbound) {
|
|
672
|
+
// Default value for a collection of elements
|
|
673
|
+
const xml = DomUtil.parse(`<xml>${child.textContent}</xml>`);
|
|
674
|
+
const json = DomUtil.toJSON(xml);
|
|
675
|
+
if(child.tagName === "translatedDefault") {
|
|
676
|
+
this.translatedDefault = XtkCaster.asArray(json[this.name]);
|
|
677
|
+
} else {
|
|
678
|
+
this.default = XtkCaster.asArray(json[this.name]);
|
|
679
|
+
}
|
|
680
|
+
} else {
|
|
681
|
+
if(child.tagName === "translatedDefault") {
|
|
682
|
+
this.translatedDefault = child.textContent;
|
|
683
|
+
} else {
|
|
684
|
+
this.default = child.textContent;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
for (const childNode of childNodes) {
|
|
690
|
+
this.children._push(childNode.name, childNode);
|
|
691
|
+
this.childrenCount = this.childrenCount + 1;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Keys (after elements and attributes have been found)
|
|
695
|
+
for (const child of EntityAccessor.getChildElements(xml, "key")) {
|
|
696
|
+
const key = new XtkSchemaKey(schema, child, this);
|
|
697
|
+
this.keys._push(key.name, key);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Propagate implicit values
|
|
701
|
+
// Name -> Label -> Desc -> HelpText
|
|
702
|
+
propagateImplicitValues(this);
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
/* create two ids that are identifying in an unique way the node label and
|
|
@@ -709,30 +709,30 @@ class XtkSchemaNode {
|
|
|
709
709
|
* nms__recipient__e____recipient__mobilePhone__@label
|
|
710
710
|
* */
|
|
711
711
|
_buildLocalizationIds() {
|
|
712
|
-
|
|
713
|
-
|
|
712
|
+
if (!this.parent) {
|
|
713
|
+
this._localizationId = this.schema.id.replace(":", "__");
|
|
714
|
+
} else {
|
|
715
|
+
this._localizationId = this.parent._localizationId;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (this.parent) {
|
|
719
|
+
// Separate each element of the path with a double _
|
|
720
|
+
if (this.isAttribute) {
|
|
721
|
+
this._localizationId = this._localizationId + "__" + this.name.replace('@', '');
|
|
714
722
|
} else {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if (this.parent) {
|
|
719
|
-
// Separate each element of the path with a double _
|
|
720
|
-
if (this.isAttribute) {
|
|
721
|
-
this._localizationId = this._localizationId + "__" + this.name.replace('@', '');
|
|
722
|
-
} else {
|
|
723
|
-
// node is not an attribute so it is an element add "e____"
|
|
724
|
-
this._localizationId = this._localizationId + "__e____" + this.name;
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
if (this.label) {
|
|
728
|
-
this.labelLocalizationId = this._localizationId + "__@label";
|
|
729
|
-
}
|
|
730
|
-
if (this.description) {
|
|
731
|
-
this.descriptionLocalizationId = this._localizationId + "__@desc";
|
|
732
|
-
}
|
|
733
|
-
if (!this.parent && this.labelSingular) {
|
|
734
|
-
this.labelSingularLocalizationId = this._localizationId + "__@labelSingular";
|
|
723
|
+
// node is not an attribute so it is an element add "e____"
|
|
724
|
+
this._localizationId = this._localizationId + "__e____" + this.name;
|
|
735
725
|
}
|
|
726
|
+
}
|
|
727
|
+
if (this.label) {
|
|
728
|
+
this.labelLocalizationId = this._localizationId + "__@label";
|
|
729
|
+
}
|
|
730
|
+
if (this.description) {
|
|
731
|
+
this.descriptionLocalizationId = this._localizationId + "__@desc";
|
|
732
|
+
}
|
|
733
|
+
if (!this.parent && this.labelSingular) {
|
|
734
|
+
this.labelSingularLocalizationId = this._localizationId + "__@labelSingular";
|
|
735
|
+
}
|
|
736
736
|
}
|
|
737
737
|
|
|
738
738
|
/**
|
|
@@ -741,7 +741,7 @@ class XtkSchemaNode {
|
|
|
741
741
|
* @returns {boolean} a boolean indicating whether the node contains a child with the given name
|
|
742
742
|
*/
|
|
743
743
|
isUnbound() {
|
|
744
|
-
|
|
744
|
+
return this.unbound;
|
|
745
745
|
}
|
|
746
746
|
|
|
747
747
|
/**
|
|
@@ -752,24 +752,24 @@ class XtkSchemaNode {
|
|
|
752
752
|
* @returns {string} the node path
|
|
753
753
|
*/
|
|
754
754
|
_getNodePath(absolute) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
755
|
+
if (absolute === undefined) absolute = true;
|
|
756
|
+
var path = !this.parent ? this.name : "";
|
|
757
|
+
var schemaName = this.schema.name;
|
|
758
|
+
var node = this;
|
|
759
|
+
while (node && node.parent) {
|
|
760
|
+
if (path != "") path = `/${path}`;
|
|
761
|
+
if (node.parent.parent || node.name != schemaName)
|
|
762
|
+
path = `${node.name}${path}`;
|
|
763
|
+
node = node.parent;
|
|
764
|
+
}
|
|
765
|
+
if (absolute) {
|
|
766
|
+
if (path == "") path = "/";
|
|
767
|
+
else if (!path.startsWith("/")) path = `/${path}`;
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
if (path.startsWith("/")) path = path.substring(1);
|
|
771
|
+
}
|
|
772
|
+
return new XPath(path);
|
|
773
773
|
}
|
|
774
774
|
|
|
775
775
|
/**
|
|
@@ -777,51 +777,51 @@ class XtkSchemaNode {
|
|
|
777
777
|
* @returns {Promise<Campaign.XtkNode>} the target node, or undefined if not found
|
|
778
778
|
*/
|
|
779
779
|
async refTarget() {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
780
|
+
if (!this.ref) return;
|
|
781
|
+
const index = this.ref.lastIndexOf(':');
|
|
782
|
+
if (index !== -1) {
|
|
783
|
+
// find the associated schame
|
|
784
|
+
const refSchemaId = this.ref.substring(0, index);
|
|
785
|
+
if (refSchemaId.indexOf(':') === -1)
|
|
786
|
+
throw Error(`Cannot find ref target '${this.ref}' from node '${this.nodePath}' of schema '${this.schema.id}': ref value is not correct (expeted <schemaId>:<path>)`);
|
|
787
|
+
const refPath = this.ref.substring(index + 1);
|
|
788
|
+
// inside current schema ?
|
|
789
|
+
if (refSchemaId === this.schema.id)
|
|
790
|
+
return this.schema.findNode(refPath);
|
|
791
|
+
const refSchema = await this.schema._application.getSchema(refSchemaId);
|
|
792
|
+
if (!refSchema) return;
|
|
793
|
+
return refSchema.findNode(refPath);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
// ref is in the current schema
|
|
797
|
+
return this.schema.findNode(this.ref);
|
|
798
|
+
}
|
|
799
799
|
}
|
|
800
800
|
|
|
801
801
|
/**
|
|
802
802
|
* Find the target of a link node.
|
|
803
803
|
* @returns {Promise<Campaign.XtkNode>} the target node, or undefined if not found
|
|
804
804
|
*/
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
805
|
+
async linkTarget() {
|
|
806
|
+
if (this.type !== "link") return this.schema.root;
|
|
807
|
+
let schemaId = this.target;
|
|
808
|
+
let xpath = "";
|
|
809
|
+
if (this.target.indexOf(',') !== -1)
|
|
810
|
+
throw new Error(`Cannot find target of link '${this.target}': target has multiple schemas`);
|
|
811
|
+
const index = this.target.indexOf('/');
|
|
812
|
+
if (index !== -1) {
|
|
813
|
+
xpath = this.target.substring(index + 1);
|
|
814
|
+
schemaId = this.target.substring(0, index);
|
|
815
|
+
xpath = this.target.substring(index + 1);
|
|
816
|
+
}
|
|
817
|
+
if (schemaId.indexOf(':') === -1)
|
|
818
|
+
throw new Error(`Cannot find target of link '${this.target}': target is not a valid link target (missing schema id)`);
|
|
819
|
+
const schema = await this.schema._application.getSchema(schemaId);
|
|
820
|
+
if (!schema) return;
|
|
821
|
+
const root = schema.root;
|
|
822
|
+
if (!root) return;
|
|
823
|
+
if (!xpath) return root;
|
|
824
|
+
return await root.findNode(xpath);
|
|
825
825
|
}
|
|
826
826
|
|
|
827
827
|
/**
|
|
@@ -831,45 +831,45 @@ class XtkSchemaNode {
|
|
|
831
831
|
* @param {XML.XPath|string} path XPath represents the name of the node to be searched
|
|
832
832
|
* @returns {Promise<XtkSchemaNode>} Returns a XtkSchemaNode instance if the node can be found
|
|
833
833
|
*/
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
834
|
+
async findNode(path) {
|
|
835
|
+
if (typeof path == "string") path = new XPath(path);
|
|
836
|
+
|
|
837
|
+
// Find the starting node
|
|
838
|
+
var node = this;
|
|
839
|
+
if (path.isEmpty() || path.isAbsolute()) {
|
|
840
|
+
node = this.schema.root;
|
|
841
|
+
if (!node) return;
|
|
842
|
+
path = path.getRelativePath();
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Special case for current path "."
|
|
846
|
+
if (path.isSelf()) return this;
|
|
847
|
+
|
|
848
|
+
const elements = path.getElements();
|
|
849
|
+
while (node && elements.length > 0) {
|
|
850
|
+
const element = elements.shift();
|
|
851
|
+
var name = element.asString();
|
|
852
|
+
|
|
853
|
+
// TODO: if the path is a collection path, ignore the collection index
|
|
854
|
+
|
|
855
|
+
// handle ref elements (consider the ref target instead)
|
|
856
|
+
if (node.ref) node = await node.refTarget();
|
|
857
|
+
if (!node) break;
|
|
858
|
+
|
|
859
|
+
if (node.type === "link") node = await node.linkTarget();
|
|
860
|
+
if (!node) break;
|
|
861
|
+
|
|
862
|
+
// Don't continue for any type
|
|
863
|
+
// kludge to accept immediate child of an ANY type node (cas in packages)
|
|
864
|
+
if (node.type === 'ANY') return this.children[name];
|
|
865
|
+
|
|
866
|
+
var childNode = null;
|
|
867
|
+
if (element.isSelf()) childNode = node;
|
|
868
|
+
else if (element.isParent()) childNode = node.parent;
|
|
869
|
+
else childNode = await node.children[name];
|
|
870
|
+
node = childNode;
|
|
871
|
+
}
|
|
872
|
+
return node;
|
|
873
873
|
}
|
|
874
874
|
|
|
875
875
|
/**
|
|
@@ -880,12 +880,12 @@ class XtkSchemaNode {
|
|
|
880
880
|
* @returns {string} a multi-line string representing the schema definition in a human readable form for troubleshooting purposes
|
|
881
881
|
*/
|
|
882
882
|
toString(indent) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
883
|
+
indent = indent || "";
|
|
884
|
+
var s = `${indent}${this.label} (${this.name})\n`;
|
|
885
|
+
for (var child of this.children) {
|
|
886
|
+
s = s + child.toString(` ${indent}`);
|
|
887
|
+
}
|
|
888
|
+
return s;
|
|
889
889
|
}
|
|
890
890
|
|
|
891
891
|
/**
|
|
@@ -893,20 +893,20 @@ class XtkSchemaNode {
|
|
|
893
893
|
* @returns {Promise<Array>} returns an array of joins. Each join is an element having a source and destination attributes, whose value is the corresponding XtkSchemaNode
|
|
894
894
|
*/
|
|
895
895
|
async joinNodes() {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
896
|
+
if (!this.isLink) return;
|
|
897
|
+
const joinParts = [];
|
|
898
|
+
for (const join of this.joins) {
|
|
899
|
+
const source = await this.parent.findNode(join.src);
|
|
900
|
+
let destination = await this.linkTarget();
|
|
901
|
+
if (destination)
|
|
902
|
+
destination = await destination.findNode(join.dst);
|
|
903
|
+
if (source && destination)
|
|
904
|
+
joinParts.push({
|
|
905
|
+
source: source,
|
|
906
|
+
destination: destination
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
return joinParts;
|
|
910
910
|
}
|
|
911
911
|
|
|
912
912
|
/**
|
|
@@ -914,32 +914,32 @@ class XtkSchemaNode {
|
|
|
914
914
|
* @returns {Promise<Campaign.XtkSchemaNode>}
|
|
915
915
|
*/
|
|
916
916
|
async reverseLink() {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
917
|
+
if (!this.isLink) return;
|
|
918
|
+
const target = await this.linkTarget();
|
|
919
|
+
if (!target) return;
|
|
920
|
+
const revLink = await target.findNode(this.revLink);
|
|
921
|
+
return revLink;
|
|
922
922
|
}
|
|
923
923
|
|
|
924
924
|
/**
|
|
925
925
|
* Returns the compute string of a node. As the node can be a link or a reference, this function is asynchronous
|
|
926
926
|
* @returns {Promise<string>}
|
|
927
927
|
*/
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
928
|
+
async computeString() {
|
|
929
|
+
if (this.expr) return this.expr;
|
|
930
|
+
// if we are a ref: ask the target of the ref
|
|
931
|
+
if (this.ref) {
|
|
932
|
+
const refTarget = await this.refTarget();
|
|
933
|
+
if (!refTarget) return "";
|
|
934
|
+
return await refTarget.computeString();
|
|
935
|
+
}
|
|
936
|
+
// No compute-string found: generate a default one (first key field)
|
|
937
|
+
if (this.keys && this.keys.length > 0) {
|
|
938
|
+
const key = this.keys[0];
|
|
939
|
+
if (key && key.fields && key.fields.length > 0 && key.fields[0])
|
|
940
|
+
return this.schema._application.client.sdk.expandXPath(key.fields[0].nodePath);
|
|
941
|
+
}
|
|
942
|
+
return "";
|
|
943
943
|
}
|
|
944
944
|
|
|
945
945
|
/**
|
|
@@ -948,10 +948,10 @@ class XtkSchemaNode {
|
|
|
948
948
|
* @returns Promise<Campaign.XtkEnumeration>
|
|
949
949
|
*/
|
|
950
950
|
async enumeration(optionalName) {
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
951
|
+
const name = optionalName || this.enum;
|
|
952
|
+
if (!name) return;
|
|
953
|
+
const enumaration = await this.schema._application.getSysEnum(name, this.schema);
|
|
954
|
+
return enumaration;
|
|
955
955
|
}
|
|
956
956
|
|
|
957
957
|
/**
|
|
@@ -959,7 +959,7 @@ class XtkSchemaNode {
|
|
|
959
959
|
* @returns {Campaign.XtkSchemaKey}
|
|
960
960
|
*/
|
|
961
961
|
firstInternalKeyDef() {
|
|
962
|
-
|
|
962
|
+
return this.keys.find((k) => k.isInternal);
|
|
963
963
|
}
|
|
964
964
|
|
|
965
965
|
/**
|
|
@@ -967,7 +967,7 @@ class XtkSchemaNode {
|
|
|
967
967
|
* @returns {Campaign.XtkSchemaKey}
|
|
968
968
|
*/
|
|
969
969
|
firstExternalKeyDef() {
|
|
970
|
-
|
|
970
|
+
return this.keys.find((k) => !k.isInternal);
|
|
971
971
|
}
|
|
972
972
|
|
|
973
973
|
/**
|
|
@@ -975,17 +975,17 @@ class XtkSchemaNode {
|
|
|
975
975
|
* @returns {Campaign.XtkSchemaKey}
|
|
976
976
|
*/
|
|
977
977
|
firstKeyDef() {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
978
|
+
let key = this.firstInternalKeyDef();
|
|
979
|
+
if (!key) key = this.firstExternalKeyDef();
|
|
980
|
+
return key;
|
|
981
981
|
}
|
|
982
|
-
}
|
|
982
|
+
}
|
|
983
983
|
|
|
984
|
-
// ========================================================================================
|
|
985
|
-
// Enumerations
|
|
986
|
-
// ========================================================================================
|
|
984
|
+
// ========================================================================================
|
|
985
|
+
// Enumerations
|
|
986
|
+
// ========================================================================================
|
|
987
987
|
|
|
988
|
-
/**
|
|
988
|
+
/**
|
|
989
989
|
* @typedef {('string'|'byte'|'short'|'long'|'boolean')} XtkEnumerationType
|
|
990
990
|
* @memberOf Campaign
|
|
991
991
|
*
|
|
@@ -994,7 +994,7 @@ class XtkSchemaNode {
|
|
|
994
994
|
*/
|
|
995
995
|
|
|
996
996
|
|
|
997
|
-
/**
|
|
997
|
+
/**
|
|
998
998
|
* A system enumeration value
|
|
999
999
|
*
|
|
1000
1000
|
* @private
|
|
@@ -1005,7 +1005,7 @@ class XtkSchemaNode {
|
|
|
1005
1005
|
* @param {string} parentTranslationId the translation id of the parent node
|
|
1006
1006
|
* @memberof Campaign
|
|
1007
1007
|
*/
|
|
1008
|
-
function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
1008
|
+
function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
1009
1009
|
/**
|
|
1010
1010
|
* The value (unique) name
|
|
1011
1011
|
* @type {string}
|
|
@@ -1028,8 +1028,8 @@ function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
|
1028
1028
|
* A human friendly long description of the value
|
|
1029
1029
|
* @type {string}
|
|
1030
1030
|
*/
|
|
1031
|
-
|
|
1032
|
-
|
|
1031
|
+
this.description = EntityAccessor.getAttributeAsString(xml, "desc");
|
|
1032
|
+
/**
|
|
1033
1033
|
* The value image (if any) or an empty string
|
|
1034
1034
|
* @type {string}
|
|
1035
1035
|
*/
|
|
@@ -1046,9 +1046,9 @@ function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
|
1046
1046
|
this.applicableIf = EntityAccessor.getAttributeAsString(xml, "applicableIf");
|
|
1047
1047
|
let stringValue = EntityAccessor.getAttributeAsString(xml, "value");
|
|
1048
1048
|
if (stringValue == "" && XtkCaster.isNumericType(baseType)) {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1049
|
+
// Some enumerations (ex: xtk:dataTransfer:decimalCount) are of numeric type but do
|
|
1050
|
+
// not have a "value" defined. In this case, we try to cas the name as the value
|
|
1051
|
+
stringValue = this.name;
|
|
1052
1052
|
}
|
|
1053
1053
|
/**
|
|
1054
1054
|
* The enumeration value, casted according to the enumeration type
|
|
@@ -1057,9 +1057,9 @@ function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
|
1057
1057
|
this.value = XtkCaster.as(stringValue, baseType);
|
|
1058
1058
|
|
|
1059
1059
|
propagateImplicitValues(this, true);
|
|
1060
|
-
}
|
|
1060
|
+
}
|
|
1061
1061
|
|
|
1062
|
-
/**
|
|
1062
|
+
/**
|
|
1063
1063
|
* A system enumeration
|
|
1064
1064
|
*
|
|
1065
1065
|
* @private
|
|
@@ -1068,96 +1068,96 @@ function XtkEnumerationValue(xml, baseType, parentTranslationId) {
|
|
|
1068
1068
|
* @param {XML.XtkObject} xml the enumeration definition
|
|
1069
1069
|
* @memberof Campaign
|
|
1070
1070
|
*/
|
|
1071
|
-
class XtkEnumeration {
|
|
1071
|
+
class XtkEnumeration {
|
|
1072
1072
|
constructor(schemaId, xml) {
|
|
1073
|
-
|
|
1073
|
+
/**
|
|
1074
1074
|
* The system enumeration name, fully qualified, i.e. prefixed with the schema id
|
|
1075
1075
|
* @type {string}
|
|
1076
1076
|
*/
|
|
1077
|
-
|
|
1077
|
+
this.name = EntityAccessor.getAttributeAsString(xml, "name");
|
|
1078
1078
|
|
|
1079
|
-
|
|
1079
|
+
/**
|
|
1080
1080
|
* A human friendly name for the system enumeration
|
|
1081
1081
|
* @type {string}
|
|
1082
1082
|
*/
|
|
1083
|
-
|
|
1083
|
+
this.label = EntityAccessor.getAttributeAsString(xml, "label");
|
|
1084
1084
|
|
|
1085
|
-
|
|
1085
|
+
/**
|
|
1086
1086
|
* A human friendly long description of the enumeration
|
|
1087
1087
|
* @type {string}
|
|
1088
1088
|
*/
|
|
1089
|
-
|
|
1089
|
+
this.description = EntityAccessor.getAttributeAsString(xml, "desc");
|
|
1090
1090
|
|
|
1091
|
-
|
|
1091
|
+
/**
|
|
1092
1092
|
* The type of the enumeration, usually "string" or "byte"
|
|
1093
1093
|
* @type {Campaign.XtkEnumerationType}
|
|
1094
1094
|
*/
|
|
1095
|
-
|
|
1095
|
+
this.baseType = EntityAccessor.getAttributeAsString(xml, "basetype");
|
|
1096
1096
|
|
|
1097
|
-
|
|
1097
|
+
/**
|
|
1098
1098
|
* The default value of the enumeration
|
|
1099
1099
|
* @type {Campaign.XtkEnumerationValue}
|
|
1100
1100
|
*/
|
|
1101
|
-
|
|
1101
|
+
this.default = null;
|
|
1102
1102
|
|
|
1103
|
-
|
|
1103
|
+
/**
|
|
1104
1104
|
* Indicates if the enumeration has an image, i.e. if any of its values has an image
|
|
1105
1105
|
* @type {boolean}
|
|
1106
1106
|
*/
|
|
1107
|
-
|
|
1107
|
+
this.hasImage = false;
|
|
1108
1108
|
|
|
1109
|
-
|
|
1109
|
+
/**
|
|
1110
1110
|
* The enumerations values
|
|
1111
1111
|
* @type {Utils.ArrayMap<Campaign.XtkEnumerationValue>}
|
|
1112
1112
|
*/
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1113
|
+
this.values = new ArrayMap();
|
|
1114
|
+
|
|
1115
|
+
var defaultValue = EntityAccessor.getAttributeAsString(xml, "default");
|
|
1116
|
+
this._localizationId = `${schemaId}__${this.name}`.replace(':','__');
|
|
1117
|
+
|
|
1118
|
+
// Determine if the enumeration can support both access by name and by index.
|
|
1119
|
+
// Some enumerations, such as xtk:dataTransfer:decimalCount are ambiguous since
|
|
1120
|
+
// they have names which are string reprensentation of their values (ex: name="0").
|
|
1121
|
+
// In this case enumValue[0] may mean either the first enumeration value (index 0)
|
|
1122
|
+
// or the enumeration value with value "0" which happens to be the second
|
|
1123
|
+
let supportsIndexing = true;
|
|
1124
|
+
const values = [];
|
|
1125
|
+
for (var child of EntityAccessor.getChildElements(xml, "value")) {
|
|
1126
|
+
const e = new XtkEnumerationValue(child, this.baseType, this._localizationId);
|
|
1127
|
+
values.push(e);
|
|
1128
|
+
const numericName = +e.name;
|
|
1129
|
+
if (numericName === numericName) {
|
|
1130
|
+
// Name is a number
|
|
1131
|
+
supportsIndexing = false;
|
|
1133
1132
|
}
|
|
1133
|
+
}
|
|
1134
1134
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1135
|
+
for (const e of values) {
|
|
1136
|
+
this.values._push(e.name, e, !supportsIndexing);
|
|
1137
|
+
if (e.image != "") this.hasImage = true;
|
|
1138
|
+
const stringValue = e.name;
|
|
1139
|
+
if (defaultValue == stringValue)
|
|
1140
|
+
this.default = e;
|
|
1141
|
+
}
|
|
1142
1142
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1143
|
+
this.labelLocalizationId = this._localizationId + "__@label";
|
|
1144
|
+
this.descriptionLocalizationId = this._localizationId + "__@desc";
|
|
1145
|
+
propagateImplicitValues(this, true);
|
|
1146
1146
|
|
|
1147
|
-
|
|
1147
|
+
/**
|
|
1148
1148
|
* The system enumeration name, without the schema id prefix
|
|
1149
1149
|
* @type {string}
|
|
1150
1150
|
*/
|
|
1151
|
-
|
|
1152
|
-
|
|
1151
|
+
this.shortName = this.name;
|
|
1152
|
+
this.name = `${schemaId}:${this.shortName}`;
|
|
1153
1153
|
}
|
|
1154
|
-
}
|
|
1154
|
+
}
|
|
1155
1155
|
|
|
1156
|
-
// ========================================================================================
|
|
1157
|
-
// Schemas
|
|
1158
|
-
// ========================================================================================
|
|
1156
|
+
// ========================================================================================
|
|
1157
|
+
// Schemas
|
|
1158
|
+
// ========================================================================================
|
|
1159
1159
|
|
|
1160
|
-
/**
|
|
1160
|
+
/**
|
|
1161
1161
|
* A schema
|
|
1162
1162
|
*
|
|
1163
1163
|
* @private
|
|
@@ -1168,82 +1168,82 @@ class XtkEnumeration {
|
|
|
1168
1168
|
* @param {XML.XtkObject} xml the schema definition
|
|
1169
1169
|
* @memberof Campaign
|
|
1170
1170
|
*/
|
|
1171
|
-
class XtkSchema extends XtkSchemaNode {
|
|
1171
|
+
class XtkSchema extends XtkSchemaNode {
|
|
1172
1172
|
|
|
1173
1173
|
constructor(application, xml) {
|
|
1174
|
-
|
|
1175
|
-
|
|
1174
|
+
super();
|
|
1175
|
+
this._application = application;
|
|
1176
1176
|
|
|
1177
|
-
|
|
1177
|
+
/**
|
|
1178
1178
|
* The namespace of the schema
|
|
1179
1179
|
* @type {string}
|
|
1180
1180
|
*/
|
|
1181
|
-
|
|
1181
|
+
this.namespace = EntityAccessor.getAttributeAsString(xml, "namespace");
|
|
1182
1182
|
|
|
1183
|
-
|
|
1183
|
+
/**
|
|
1184
1184
|
* The schema id, in the form "namespace:name"
|
|
1185
1185
|
* @type {string}
|
|
1186
1186
|
*/
|
|
1187
|
-
|
|
1188
|
-
|
|
1187
|
+
this.name = EntityAccessor.getAttributeAsString(xml, "name");
|
|
1188
|
+
this.id = `${this.namespace}:${this.name}`;
|
|
1189
1189
|
|
|
1190
|
-
|
|
1190
|
+
/**
|
|
1191
1191
|
* Indicates whether the schema is a library schema or not
|
|
1192
1192
|
* @type {boolean}
|
|
1193
1193
|
*/
|
|
1194
|
-
|
|
1194
|
+
this.isLibrary = EntityAccessor.getAttributeAsBoolean(xml, "library");
|
|
1195
1195
|
|
|
1196
|
-
|
|
1196
|
+
/**
|
|
1197
1197
|
* A human name for the schema, in singular
|
|
1198
1198
|
* @type {string}
|
|
1199
1199
|
*/
|
|
1200
|
-
|
|
1201
|
-
|
|
1200
|
+
this.labelSingular = EntityAccessor.getAttributeAsString(xml, "labelSingular");
|
|
1201
|
+
/**
|
|
1202
1202
|
* The schema mappgin type, following the xtk:srcSchema:mappingType enumeration
|
|
1203
1203
|
* @type {Campaign.XtkSchemaMappingType}
|
|
1204
1204
|
*/
|
|
1205
|
-
|
|
1205
|
+
this.mappingType = EntityAccessor.getAttributeAsString(xml, "mappingType");
|
|
1206
1206
|
|
|
1207
|
-
|
|
1207
|
+
/**
|
|
1208
1208
|
* The MD5 checksum of the schema in the form of a hexadecimal string
|
|
1209
1209
|
* @type {string}
|
|
1210
1210
|
*/
|
|
1211
|
-
|
|
1211
|
+
this.md5 = EntityAccessor.getAttributeAsString(xml, "md5");
|
|
1212
1212
|
|
|
1213
|
-
|
|
1213
|
+
/**
|
|
1214
1214
|
* The schema definition
|
|
1215
1215
|
* @private
|
|
1216
1216
|
* @type {XML.XtkObject}
|
|
1217
1217
|
*/
|
|
1218
|
-
|
|
1218
|
+
this.xml = xml;
|
|
1219
1219
|
|
|
1220
|
-
|
|
1220
|
+
this.init(this, xml);
|
|
1221
1221
|
|
|
1222
|
-
|
|
1222
|
+
/**
|
|
1223
1223
|
* The schema root node, if it has one, i.e. the first child whose name matches the schema name
|
|
1224
1224
|
* @type {Campaign.XtkSchemaNode}
|
|
1225
1225
|
*/
|
|
1226
|
-
|
|
1226
|
+
this.root = this.children[this.name];
|
|
1227
1227
|
|
|
1228
|
-
|
|
1228
|
+
/**
|
|
1229
1229
|
* A user desciption of the node, in the form "label (name)"
|
|
1230
1230
|
* @type {string}
|
|
1231
1231
|
*/
|
|
1232
|
-
|
|
1232
|
+
this.userDescription = (this.label == this.name) ? this.name : `${this.label} (${this.name})`;
|
|
1233
1233
|
|
|
1234
|
-
|
|
1234
|
+
/**
|
|
1235
1235
|
* Enumerations in this schema, as a dictionary whose keys are enumeration names and values are the
|
|
1236
1236
|
* corresponding enumeration definitions
|
|
1237
1237
|
* @type {Utils.ArrayMap<Campaign.XtkEnumeration>}
|
|
1238
1238
|
*/
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1239
|
+
this.enumerations = new ArrayMap();
|
|
1240
|
+
for (var child of EntityAccessor.getChildElements(xml, "enumeration")) {
|
|
1241
|
+
const e = new XtkEnumeration(this.id, child);
|
|
1242
|
+
if (this.enumerations.get(e.shortName) === undefined) {
|
|
1243
|
+
this.enumerations._push(e.shortName, e);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
1247
|
|
|
1248
1248
|
/**
|
|
1249
1249
|
* Creates a multi-line debug string representing the schema
|
|
@@ -1251,21 +1251,21 @@ class XtkSchema extends XtkSchemaNode {
|
|
|
1251
1251
|
* @returns {string} a multi-line string representing the schema definition in a human readable form for troubleshooting purposes
|
|
1252
1252
|
*/
|
|
1253
1253
|
toString() {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1254
|
+
var s = `${this.userDescription}\n`;
|
|
1255
|
+
for (var child of this.children) {
|
|
1256
|
+
s = s + child.toString(" - ");
|
|
1257
|
+
}
|
|
1258
|
+
return s;
|
|
1259
1259
|
}
|
|
1260
|
-
}
|
|
1260
|
+
}
|
|
1261
1261
|
|
|
1262
1262
|
|
|
1263
1263
|
|
|
1264
|
-
// ========================================================================================
|
|
1265
|
-
// Current Login
|
|
1266
|
-
// ========================================================================================
|
|
1264
|
+
// ========================================================================================
|
|
1265
|
+
// Current Login
|
|
1266
|
+
// ========================================================================================
|
|
1267
1267
|
|
|
1268
|
-
/**
|
|
1268
|
+
/**
|
|
1269
1269
|
* Represents the currently logged operator. Do not create directly, this is available
|
|
1270
1270
|
* as the sdk.application.operator variable
|
|
1271
1271
|
*
|
|
@@ -1275,50 +1275,50 @@ class XtkSchema extends XtkSchemaNode {
|
|
|
1275
1275
|
* @param {XML.XtkObject} userInfo the user info object as returned from the xtk:session#Logon call
|
|
1276
1276
|
* @memberof Campaign
|
|
1277
1277
|
*/
|
|
1278
|
-
class CurrentLogin {
|
|
1278
|
+
class CurrentLogin {
|
|
1279
1279
|
|
|
1280
1280
|
constructor(userInfo) {
|
|
1281
|
-
|
|
1281
|
+
/**
|
|
1282
1282
|
* The operator login name
|
|
1283
1283
|
* @type {string}
|
|
1284
1284
|
*/
|
|
1285
|
-
|
|
1285
|
+
this.login = EntityAccessor.getAttributeAsString(userInfo, "login");
|
|
1286
1286
|
|
|
1287
|
-
|
|
1287
|
+
/**
|
|
1288
1288
|
* The operator login id
|
|
1289
1289
|
* @type {number}
|
|
1290
1290
|
*/
|
|
1291
|
-
|
|
1291
|
+
this.id = EntityAccessor.getAttributeAsLong(userInfo, "loginId");
|
|
1292
1292
|
|
|
1293
|
-
|
|
1293
|
+
/**
|
|
1294
1294
|
* A human friendly string naming the operator (compute string)
|
|
1295
1295
|
* @type {string}
|
|
1296
1296
|
*/
|
|
1297
|
-
|
|
1297
|
+
this.computeString = EntityAccessor.getAttributeAsString(userInfo, "loginCS");
|
|
1298
1298
|
|
|
1299
|
-
|
|
1299
|
+
/**
|
|
1300
1300
|
* The operator timezone
|
|
1301
1301
|
* @type {string}
|
|
1302
1302
|
*/
|
|
1303
|
-
|
|
1303
|
+
this.timezone = EntityAccessor.getAttributeAsString(userInfo, "timezone");
|
|
1304
1304
|
|
|
1305
|
-
|
|
1305
|
+
/**
|
|
1306
1306
|
* The instance locale
|
|
1307
1307
|
* @type { string }
|
|
1308
1308
|
*/
|
|
1309
|
-
|
|
1309
|
+
this.instanceLocale = EntityAccessor.getAttributeAsString(userInfo, "instanceLocale");
|
|
1310
1310
|
|
|
1311
|
-
|
|
1311
|
+
/**
|
|
1312
1312
|
* The llist of operator rights
|
|
1313
1313
|
* @type {string[]}
|
|
1314
1314
|
*/
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1315
|
+
this.rights = [];
|
|
1316
|
+
this._rightsSet = {};
|
|
1317
|
+
for (var child of EntityAccessor.getChildElements(userInfo, "login-right")) {
|
|
1318
|
+
const right = EntityAccessor.getAttributeAsString(child, "right");
|
|
1319
1319
|
this.rights.push(right);
|
|
1320
1320
|
this._rightsSet[right] = true;
|
|
1321
|
-
|
|
1321
|
+
}
|
|
1322
1322
|
}
|
|
1323
1323
|
|
|
1324
1324
|
/**
|
|
@@ -1328,12 +1328,12 @@ class CurrentLogin {
|
|
|
1328
1328
|
* @returns {boolean} a boolean indicating whether the operator has the given right or not
|
|
1329
1329
|
*/
|
|
1330
1330
|
hasRight(name) {
|
|
1331
|
-
|
|
1331
|
+
return !!this._rightsSet[name];
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
|
-
}
|
|
1334
|
+
}
|
|
1335
1335
|
|
|
1336
|
-
/**
|
|
1336
|
+
/**
|
|
1337
1337
|
* Creates a current login object for testing purposes
|
|
1338
1338
|
*
|
|
1339
1339
|
* @private
|
|
@@ -1341,21 +1341,21 @@ class CurrentLogin {
|
|
|
1341
1341
|
* @returns the CurrentLogin object corresponding to the passed object
|
|
1342
1342
|
* @memberof Campaign
|
|
1343
1343
|
*/
|
|
1344
|
-
function newCurrentLogin(userInfo) {
|
|
1344
|
+
function newCurrentLogin(userInfo) {
|
|
1345
1345
|
return new CurrentLogin(userInfo);
|
|
1346
|
-
}
|
|
1346
|
+
}
|
|
1347
1347
|
|
|
1348
|
-
// ========================================================================================
|
|
1349
|
-
// Application
|
|
1350
|
-
// ========================================================================================
|
|
1348
|
+
// ========================================================================================
|
|
1349
|
+
// Application
|
|
1350
|
+
// ========================================================================================
|
|
1351
1351
|
|
|
1352
|
-
/**
|
|
1352
|
+
/**
|
|
1353
1353
|
* @class
|
|
1354
1354
|
* @constructor
|
|
1355
1355
|
* @param {Campaign.Client} client The Campaign Client from which this Application object is created
|
|
1356
1356
|
* @memberof Campaign
|
|
1357
1357
|
*/
|
|
1358
|
-
class Application {
|
|
1358
|
+
class Application {
|
|
1359
1359
|
|
|
1360
1360
|
/**
|
|
1361
1361
|
* The Application object provides access to certain properties of the Campaign server.
|
|
@@ -1364,55 +1364,55 @@ class Application {
|
|
|
1364
1364
|
* @param {Campaign.Client} client the Campaign client representing the Campaign instance
|
|
1365
1365
|
*/
|
|
1366
1366
|
constructor(client) {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1367
|
+
this.client = client;
|
|
1368
|
+
this._schemaCache = new SchemaCache(client);
|
|
1369
|
+
const info = this.client.getSessionInfo();
|
|
1370
|
+
// When using "SessionToken" authentication, there is no actual logon, and therefore
|
|
1371
|
+
// no "sessionInfo" object
|
|
1372
|
+
if (info) {
|
|
1373
|
+
const serverInfo = EntityAccessor.getElement(info, "serverInfo");
|
|
1374
|
+
/**
|
|
1375
1375
|
* The server build number
|
|
1376
1376
|
* @type {string}
|
|
1377
1377
|
*/
|
|
1378
|
-
|
|
1379
|
-
|
|
1378
|
+
this.buildNumber = EntityAccessor.getAttributeAsString(serverInfo, "buildNumber");
|
|
1379
|
+
/**
|
|
1380
1380
|
* The server version, formatted as major.minor.servicePack (ex: 8.2.10)
|
|
1381
1381
|
* @type {string}
|
|
1382
1382
|
*/
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1383
|
+
const majNumber = EntityAccessor.getAttributeAsString(serverInfo, "majNumber");
|
|
1384
|
+
const minNumber = EntityAccessor.getAttributeAsString(serverInfo, "minNumber");
|
|
1385
|
+
const servicePack = EntityAccessor.getAttributeAsString(serverInfo, "servicePack");
|
|
1386
|
+
if (majNumber && minNumber && servicePack)
|
|
1387
|
+
this.version = majNumber + "." + minNumber + "." + servicePack;
|
|
1388
|
+
/**
|
|
1389
1389
|
* The Campaign instance name
|
|
1390
1390
|
* @type {string}
|
|
1391
1391
|
*/
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1392
|
+
this.instanceName = EntityAccessor.getAttributeAsString(serverInfo, "instanceName");
|
|
1393
|
+
const userInfo = EntityAccessor.getElement(info, "userInfo");
|
|
1394
|
+
/**
|
|
1395
1395
|
* The logged operator
|
|
1396
1396
|
* @type {Campaign.CurrentLogin}
|
|
1397
1397
|
*/
|
|
1398
|
-
|
|
1399
|
-
|
|
1398
|
+
this.operator = new CurrentLogin(userInfo);
|
|
1399
|
+
/**
|
|
1400
1400
|
* The list of installed packages
|
|
1401
1401
|
* @type {string[]}
|
|
1402
1402
|
*/
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
}
|
|
1403
|
+
this.packages = [];
|
|
1404
|
+
for (var p of EntityAccessor.getChildElements(userInfo, "installed-package")) {
|
|
1405
|
+
this.packages.push(`${EntityAccessor.getAttributeAsString(p, "namespace")}:${EntityAccessor.getAttributeAsString(p, "name")}`);
|
|
1407
1406
|
}
|
|
1407
|
+
}
|
|
1408
1408
|
}
|
|
1409
1409
|
|
|
1410
1410
|
_registerCacheChangeListener() {
|
|
1411
|
-
|
|
1411
|
+
this.client._registerCacheChangeListener(this._schemaCache);
|
|
1412
1412
|
}
|
|
1413
1413
|
|
|
1414
1414
|
_unregisterCacheChangeListener() {
|
|
1415
|
-
|
|
1415
|
+
this.client._unregisterCacheChangeListener(this._schemaCache);
|
|
1416
1416
|
}
|
|
1417
1417
|
/**
|
|
1418
1418
|
* Get a schema by id. This function returns an XtkSchema object or null if the schema is not found.
|
|
@@ -1422,19 +1422,19 @@ class Application {
|
|
|
1422
1422
|
* @param {boolean} withoutCache if true, the schema will be fetched from the server without using the cache, defaults to false
|
|
1423
1423
|
* @returns {Campaign.XtkSchema} the schema, or null if the schema was not found
|
|
1424
1424
|
*/
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1425
|
+
async getSchema(schemaId, withoutCache = false) {
|
|
1426
|
+
if (withoutCache) {
|
|
1427
|
+
return this._getSchema(schemaId, withoutCache);
|
|
1428
|
+
}
|
|
1429
|
+
return this._schemaCache.getSchema(schemaId);
|
|
1430
1430
|
}
|
|
1431
1431
|
|
|
1432
1432
|
// Private function: get a schema without using the SchemaCache
|
|
1433
1433
|
async _getSchema(schemaId, withoutCache = false) {
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1434
|
+
const xml = await this.client.getSchema(schemaId, "xml", undefined, withoutCache);
|
|
1435
|
+
if (!xml)
|
|
1436
|
+
return null;
|
|
1437
|
+
return newSchema(xml, this);
|
|
1438
1438
|
}
|
|
1439
1439
|
|
|
1440
1440
|
/**
|
|
@@ -1444,10 +1444,10 @@ class Application {
|
|
|
1444
1444
|
* @returns {boolean} a boolean indicating whether the package is installed or not
|
|
1445
1445
|
*/
|
|
1446
1446
|
hasPackage(name) {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1447
|
+
for (var p of this.packages) {
|
|
1448
|
+
if (p == name) return true;
|
|
1449
|
+
}
|
|
1450
|
+
return false;
|
|
1451
1451
|
}
|
|
1452
1452
|
|
|
1453
1453
|
/**
|
|
@@ -1458,32 +1458,32 @@ class Application {
|
|
|
1458
1458
|
* @returns {XtkEnumeration} the enumeration
|
|
1459
1459
|
*/
|
|
1460
1460
|
async getSysEnum(enumerationName, schemaOrSchemaId) {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
if (!schema) return;
|
|
1468
|
-
return schema.enumerations[enumerationName];
|
|
1469
|
-
}
|
|
1470
|
-
// qualified enumeration name
|
|
1471
|
-
const schemaId = enumerationName.substring(0, index);
|
|
1472
|
-
if (schemaId.indexOf(':') === -1)
|
|
1473
|
-
throw Error(`Invalid enumeration name '${enumerationName}': expecting {name} or {schemaId}:{name}`);
|
|
1474
|
-
let schema = await this.getSchema(schemaId);
|
|
1461
|
+
const index = enumerationName.lastIndexOf(':');
|
|
1462
|
+
if (index === -1) {
|
|
1463
|
+
let schema = schemaOrSchemaId;
|
|
1464
|
+
if (schema && typeof schema === "string")
|
|
1465
|
+
schema = await this.getSchema(schema);
|
|
1466
|
+
// unqualified enumeration name
|
|
1475
1467
|
if (!schema) return;
|
|
1476
|
-
return schema.enumerations[enumerationName
|
|
1468
|
+
return schema.enumerations[enumerationName];
|
|
1469
|
+
}
|
|
1470
|
+
// qualified enumeration name
|
|
1471
|
+
const schemaId = enumerationName.substring(0, index);
|
|
1472
|
+
if (schemaId.indexOf(':') === -1)
|
|
1473
|
+
throw Error(`Invalid enumeration name '${enumerationName}': expecting {name} or {schemaId}:{name}`);
|
|
1474
|
+
let schema = await this.getSchema(schemaId);
|
|
1475
|
+
if (!schema) return;
|
|
1476
|
+
return schema.enumerations[enumerationName.substring(index + 1)];
|
|
1477
1477
|
}
|
|
1478
|
-
}
|
|
1478
|
+
}
|
|
1479
1479
|
|
|
1480
1480
|
|
|
1481
1481
|
|
|
1482
|
-
// Public exports
|
|
1483
|
-
exports.Application = Application;
|
|
1482
|
+
// Public exports
|
|
1483
|
+
exports.Application = Application;
|
|
1484
1484
|
|
|
1485
|
-
// For tests
|
|
1486
|
-
exports.newSchema = newSchema;
|
|
1487
|
-
exports.newCurrentLogin = newCurrentLogin;
|
|
1488
|
-
exports.SchemaCache = SchemaCache;
|
|
1485
|
+
// For tests
|
|
1486
|
+
exports.newSchema = newSchema;
|
|
1487
|
+
exports.newCurrentLogin = newCurrentLogin;
|
|
1488
|
+
exports.SchemaCache = SchemaCache;
|
|
1489
1489
|
})();
|