@arpproject/vibearp-mcp 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/LICENSE.md +202 -0
- package/README.md +158 -0
- package/lib/dashboard/static/dashboard.css +1611 -0
- package/lib/dashboard/static/dashboard.js +2402 -0
- package/lib/dashboard/static/index.html +569 -0
- package/lib/server.js +70099 -0
- package/lib/server.js.map +7 -0
- package/lib/shutdown.js +345 -0
- package/lib/shutdown.js.map +7 -0
- package/node_modules/cedar-template-converter/LICENSE.md +202 -0
- package/node_modules/cedar-template-converter/dist/cedar-converter.d.ts +139 -0
- package/node_modules/cedar-template-converter/dist/cedar-converter.d.ts.map +1 -0
- package/node_modules/cedar-template-converter/dist/cedar-converter.js +765 -0
- package/node_modules/cedar-template-converter/dist/cedar-converter.js.map +1 -0
- package/node_modules/cedar-template-converter/package.json +33 -0
- package/package.json +53 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
// ******************************************************************************************
|
|
2
|
+
// Copyright (C) 2025-2026 SZTAKI, Department of Distributed Systems (https://dsd.sztaki.hu).
|
|
3
|
+
//
|
|
4
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
// ******************************************************************************************
|
|
6
|
+
/**
|
|
7
|
+
* TypeScript conversion of CedarTemplateToDescriboProfileConverter.java
|
|
8
|
+
* Converts CEDAR templates to Describo profile format
|
|
9
|
+
*/
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// JsonHelper Utilities
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Returns a JSON sub-element from the given JSON object and path
|
|
15
|
+
* @param json - a JSON object
|
|
16
|
+
* @param path - a JSON path, e.g. "a.b.c[2].d"
|
|
17
|
+
* @returns - a sub-element of json according to the given path, or null/undefined
|
|
18
|
+
*/
|
|
19
|
+
function getJsonElement(json, path) {
|
|
20
|
+
const parts = path.split(/\.|\[|\]/);
|
|
21
|
+
let result = json;
|
|
22
|
+
for (const key of parts) {
|
|
23
|
+
const trimmedKey = key.trim();
|
|
24
|
+
if (trimmedKey === '') {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (result == null) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(result)) {
|
|
31
|
+
const ix = parseInt(trimmedKey, 10);
|
|
32
|
+
result = result[ix];
|
|
33
|
+
}
|
|
34
|
+
else if (typeof result === 'object' && result !== null) {
|
|
35
|
+
result = result[trimmedKey];
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract a string array from a JSON path
|
|
45
|
+
* @param json - a JSON object
|
|
46
|
+
* @param path - a JSON path
|
|
47
|
+
* @returns - array of strings, or empty array if not found
|
|
48
|
+
*/
|
|
49
|
+
function getStringList(json, path) {
|
|
50
|
+
const jsonElement = getJsonElement(json, path);
|
|
51
|
+
if (jsonElement == null) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(jsonElement)) {
|
|
55
|
+
return jsonElement;
|
|
56
|
+
}
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get a JSON object from a path
|
|
61
|
+
* @param json - a JSON object
|
|
62
|
+
* @param path - a JSON path
|
|
63
|
+
* @returns - JSON object or null
|
|
64
|
+
*/
|
|
65
|
+
function getJsonObject(json, path) {
|
|
66
|
+
const jsonElement = getJsonElement(json, path);
|
|
67
|
+
if (jsonElement == null || typeof jsonElement !== 'object' || Array.isArray(jsonElement)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return jsonElement;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get a JSON array from a path
|
|
74
|
+
* @param json - a JSON object
|
|
75
|
+
* @param path - a JSON path
|
|
76
|
+
* @returns - JSON array or null
|
|
77
|
+
*/
|
|
78
|
+
function getJsonArray(json, path) {
|
|
79
|
+
const jsonElement = getJsonElement(json, path);
|
|
80
|
+
if (jsonElement == null || !Array.isArray(jsonElement)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return jsonElement;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a JSON element exists at the given path
|
|
87
|
+
* @param json - a JSON object
|
|
88
|
+
* @param path - a JSON path
|
|
89
|
+
* @returns - true if element exists, false otherwise
|
|
90
|
+
*/
|
|
91
|
+
function hasJsonElement(json, path) {
|
|
92
|
+
try {
|
|
93
|
+
return getJsonElement(json, path) != null;
|
|
94
|
+
}
|
|
95
|
+
catch (ex) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// ArpService Methods (stubbed for external vocabulary)
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Check if field has external vocabulary values
|
|
104
|
+
* @param cedarFieldTemplate - CEDAR field template
|
|
105
|
+
* @returns - always false (external vocab processing skipped)
|
|
106
|
+
*/
|
|
107
|
+
function hasExternalValues(cedarFieldTemplate) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if field is deprecated
|
|
112
|
+
* @param cedarFieldTemplate - CEDAR field template
|
|
113
|
+
* @returns - true if field is deprecated, false otherwise
|
|
114
|
+
*/
|
|
115
|
+
function isDeprecatedField(cedarFieldTemplate) {
|
|
116
|
+
const deprecatedField = getJsonElement(cedarFieldTemplate, '_arp.dataverse.deprecated');
|
|
117
|
+
return deprecatedField != null && deprecatedField !== false && deprecatedField === true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get external vocabulary values
|
|
121
|
+
* @param cedarFieldTemplate - CEDAR field template
|
|
122
|
+
* @returns - always empty array (external vocab processing skipped)
|
|
123
|
+
*/
|
|
124
|
+
function getExternalVocabValues(cedarFieldTemplate) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Inner Classes
|
|
129
|
+
// ============================================================================
|
|
130
|
+
/**
|
|
131
|
+
* DescriboInput class representing a single input field
|
|
132
|
+
*/
|
|
133
|
+
class DescriboInput {
|
|
134
|
+
_id;
|
|
135
|
+
_name;
|
|
136
|
+
_label;
|
|
137
|
+
_help;
|
|
138
|
+
_type;
|
|
139
|
+
_values;
|
|
140
|
+
_required = false;
|
|
141
|
+
_multiple = false;
|
|
142
|
+
_minValue;
|
|
143
|
+
_maxValue;
|
|
144
|
+
_minLength;
|
|
145
|
+
_maxLength;
|
|
146
|
+
_regex;
|
|
147
|
+
_placeholder;
|
|
148
|
+
_numberType;
|
|
149
|
+
_dateFormat;
|
|
150
|
+
_style;
|
|
151
|
+
_deprecated = false;
|
|
152
|
+
constructor() { }
|
|
153
|
+
isDeprecated() {
|
|
154
|
+
return this._deprecated;
|
|
155
|
+
}
|
|
156
|
+
setDeprecated(deprecated) {
|
|
157
|
+
this._deprecated = deprecated;
|
|
158
|
+
}
|
|
159
|
+
getId() {
|
|
160
|
+
return this._id;
|
|
161
|
+
}
|
|
162
|
+
setId(id) {
|
|
163
|
+
this._id = id;
|
|
164
|
+
}
|
|
165
|
+
getName() {
|
|
166
|
+
return this._name;
|
|
167
|
+
}
|
|
168
|
+
setName(name) {
|
|
169
|
+
this._name = name;
|
|
170
|
+
}
|
|
171
|
+
getLabel() {
|
|
172
|
+
return this._label;
|
|
173
|
+
}
|
|
174
|
+
setLabel(label) {
|
|
175
|
+
this._label = label;
|
|
176
|
+
}
|
|
177
|
+
getHelp() {
|
|
178
|
+
return this._help;
|
|
179
|
+
}
|
|
180
|
+
setHelp(help) {
|
|
181
|
+
this._help = help;
|
|
182
|
+
}
|
|
183
|
+
getType() {
|
|
184
|
+
return this._type;
|
|
185
|
+
}
|
|
186
|
+
setType(type) {
|
|
187
|
+
this._type = type;
|
|
188
|
+
}
|
|
189
|
+
isRequired() {
|
|
190
|
+
return this._required;
|
|
191
|
+
}
|
|
192
|
+
setRequired(required) {
|
|
193
|
+
this._required = required;
|
|
194
|
+
}
|
|
195
|
+
isMultiple() {
|
|
196
|
+
return this._multiple;
|
|
197
|
+
}
|
|
198
|
+
setMultiple(multiple) {
|
|
199
|
+
this._multiple = multiple;
|
|
200
|
+
}
|
|
201
|
+
getValues() {
|
|
202
|
+
return this._values;
|
|
203
|
+
}
|
|
204
|
+
setValues(values) {
|
|
205
|
+
this._values = values;
|
|
206
|
+
}
|
|
207
|
+
getMinValue() {
|
|
208
|
+
return this._minValue;
|
|
209
|
+
}
|
|
210
|
+
setMinValue(minValue) {
|
|
211
|
+
this._minValue = minValue;
|
|
212
|
+
}
|
|
213
|
+
getMaxValue() {
|
|
214
|
+
return this._maxValue;
|
|
215
|
+
}
|
|
216
|
+
setMaxValue(maxValue) {
|
|
217
|
+
this._maxValue = maxValue;
|
|
218
|
+
}
|
|
219
|
+
getMinLength() {
|
|
220
|
+
return this._minLength;
|
|
221
|
+
}
|
|
222
|
+
setMinLength(minLength) {
|
|
223
|
+
this._minLength = minLength;
|
|
224
|
+
}
|
|
225
|
+
getMaxLength() {
|
|
226
|
+
return this._maxLength;
|
|
227
|
+
}
|
|
228
|
+
setMaxLength(maxLength) {
|
|
229
|
+
this._maxLength = maxLength;
|
|
230
|
+
}
|
|
231
|
+
getRegex() {
|
|
232
|
+
return this._regex;
|
|
233
|
+
}
|
|
234
|
+
setRegex(regex) {
|
|
235
|
+
this._regex = regex;
|
|
236
|
+
}
|
|
237
|
+
getPlaceholder() {
|
|
238
|
+
return this._placeholder;
|
|
239
|
+
}
|
|
240
|
+
setPlaceholder(placeholder) {
|
|
241
|
+
this._placeholder = placeholder;
|
|
242
|
+
}
|
|
243
|
+
getNumberType() {
|
|
244
|
+
return this._numberType;
|
|
245
|
+
}
|
|
246
|
+
setNumberType(numberType) {
|
|
247
|
+
this._numberType = numberType;
|
|
248
|
+
}
|
|
249
|
+
getDateFormat() {
|
|
250
|
+
return this._dateFormat;
|
|
251
|
+
}
|
|
252
|
+
setDateFormat(dateFormat) {
|
|
253
|
+
this._dateFormat = dateFormat;
|
|
254
|
+
}
|
|
255
|
+
getStyle() {
|
|
256
|
+
return this._style;
|
|
257
|
+
}
|
|
258
|
+
setStyle(style) {
|
|
259
|
+
this._style = style;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Convert DescriboInput to plain object for JSON serialization
|
|
263
|
+
*/
|
|
264
|
+
toJSON() {
|
|
265
|
+
const obj = {};
|
|
266
|
+
if (this._id !== undefined)
|
|
267
|
+
obj.id = this._id;
|
|
268
|
+
if (this._name !== undefined)
|
|
269
|
+
obj.name = this._name;
|
|
270
|
+
if (this._label !== undefined)
|
|
271
|
+
obj.label = this._label;
|
|
272
|
+
if (this._help !== undefined)
|
|
273
|
+
obj.help = this._help;
|
|
274
|
+
if (this._type !== undefined)
|
|
275
|
+
obj.type = this._type;
|
|
276
|
+
if (this._values !== undefined)
|
|
277
|
+
obj.values = this._values;
|
|
278
|
+
// Always include boolean properties (even when false)
|
|
279
|
+
obj.required = this._required;
|
|
280
|
+
obj.multiple = this._multiple;
|
|
281
|
+
obj.deprecated = this._deprecated;
|
|
282
|
+
if (this._minValue !== undefined)
|
|
283
|
+
obj.minValue = this._minValue;
|
|
284
|
+
if (this._maxValue !== undefined)
|
|
285
|
+
obj.maxValue = this._maxValue;
|
|
286
|
+
if (this._minLength !== undefined)
|
|
287
|
+
obj.minLength = this._minLength;
|
|
288
|
+
if (this._maxLength !== undefined)
|
|
289
|
+
obj.maxLength = this._maxLength;
|
|
290
|
+
if (this._regex !== undefined)
|
|
291
|
+
obj.regex = this._regex;
|
|
292
|
+
if (this._placeholder !== undefined)
|
|
293
|
+
obj.placeholder = this._placeholder;
|
|
294
|
+
if (this._numberType !== undefined)
|
|
295
|
+
obj.numberType = this._numberType;
|
|
296
|
+
if (this._dateFormat !== undefined)
|
|
297
|
+
obj.dateFormat = this._dateFormat;
|
|
298
|
+
if (this._style !== undefined)
|
|
299
|
+
obj.style = this._style;
|
|
300
|
+
return obj;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* ClassLocalization for storing label and help text
|
|
305
|
+
*/
|
|
306
|
+
class ClassLocalization {
|
|
307
|
+
label;
|
|
308
|
+
help;
|
|
309
|
+
constructor(label, help) {
|
|
310
|
+
this.label = label;
|
|
311
|
+
this.help = help;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* ProcessedDescriboProfileValues for storing intermediate processing results
|
|
316
|
+
*/
|
|
317
|
+
class ProcessedDescriboProfileValues {
|
|
318
|
+
inputs = [];
|
|
319
|
+
classLocalizations = new Map();
|
|
320
|
+
constructor(inputs) {
|
|
321
|
+
this.inputs = inputs;
|
|
322
|
+
}
|
|
323
|
+
getInputs() {
|
|
324
|
+
return this.inputs;
|
|
325
|
+
}
|
|
326
|
+
setInputs(inputs) {
|
|
327
|
+
this.inputs = inputs;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// ============================================================================
|
|
331
|
+
// Main Converter Class
|
|
332
|
+
// ============================================================================
|
|
333
|
+
export class CedarTemplateToDescriboProfileConverter {
|
|
334
|
+
language;
|
|
335
|
+
cedarDescriboFieldTypes;
|
|
336
|
+
cedarDescriboNumberTypes;
|
|
337
|
+
cedarDescriboDateTypes;
|
|
338
|
+
constructor(language) {
|
|
339
|
+
this.language = language ?? 'en';
|
|
340
|
+
// Initialize field type mappings
|
|
341
|
+
this.cedarDescriboFieldTypes = new Map([
|
|
342
|
+
['textfield', ['Text']],
|
|
343
|
+
['temporal', ['Date']],
|
|
344
|
+
['numeric', ['Number']],
|
|
345
|
+
['richtext', ['TextArea']],
|
|
346
|
+
['textarea', ['TextArea']],
|
|
347
|
+
['link', ['URL']],
|
|
348
|
+
['list', ['Select']],
|
|
349
|
+
['radio', ['Select']],
|
|
350
|
+
['phone-number', ['Text']],
|
|
351
|
+
['email', ['Text']],
|
|
352
|
+
['checkbox', ['Select']] // Checkbox is mapped to Select
|
|
353
|
+
]);
|
|
354
|
+
this.cedarDescriboNumberTypes = new Map([
|
|
355
|
+
['xsd:decimal', ['Any']],
|
|
356
|
+
['xsd:long', ['Long']],
|
|
357
|
+
['xsd:int', ['Int']],
|
|
358
|
+
['xsd:double', ['Double']],
|
|
359
|
+
['xsd:float', ['Float']]
|
|
360
|
+
]);
|
|
361
|
+
this.cedarDescriboDateTypes = new Map([
|
|
362
|
+
['xsd:dateTime', ['DateTime']],
|
|
363
|
+
['xsd:date', ['Date']],
|
|
364
|
+
['xsd:time', ['Time']]
|
|
365
|
+
]);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Main conversion method - converts CEDAR template to Describo profile
|
|
369
|
+
* @param cedarTemplate - CEDAR template as JSON string
|
|
370
|
+
* @returns - Describo profile as JSON string
|
|
371
|
+
*/
|
|
372
|
+
processCedarTemplate(cedarTemplate) {
|
|
373
|
+
const describoProfileTemplate = {
|
|
374
|
+
metadata: {
|
|
375
|
+
name: 'Cedar to Describo generated profile',
|
|
376
|
+
version: 1.0,
|
|
377
|
+
description: 'Generated Describo schema from a Cedar template',
|
|
378
|
+
warnMissingProperty: true
|
|
379
|
+
},
|
|
380
|
+
classes: {
|
|
381
|
+
Dataset: {
|
|
382
|
+
definition: 'override',
|
|
383
|
+
subClassOf: [],
|
|
384
|
+
inputs: []
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
enabledClasses: ['Dataset']
|
|
388
|
+
};
|
|
389
|
+
const classTemplate = {
|
|
390
|
+
definition: 'override',
|
|
391
|
+
subClassOf: [],
|
|
392
|
+
inputs: []
|
|
393
|
+
};
|
|
394
|
+
const describoProfile = JSON.parse(JSON.stringify(describoProfileTemplate));
|
|
395
|
+
const cedarTemplateJson = JSON.parse(cedarTemplate);
|
|
396
|
+
this.processProfileMetadata(cedarTemplateJson, describoProfile);
|
|
397
|
+
const profValues = this.processTemplate(cedarTemplateJson, new ProcessedDescriboProfileValues([]), 'Dataset');
|
|
398
|
+
// Add default values for builtin types
|
|
399
|
+
if (this.language === 'hu') {
|
|
400
|
+
profValues.classLocalizations.set('Dataset', new ClassLocalization('Adatcsomag', 'Fájlok és metaadataik adatcsomagja'));
|
|
401
|
+
profValues.classLocalizations.set('File', new ClassLocalization('Fájl', 'Adatfájl'));
|
|
402
|
+
profValues.classLocalizations.set('Text', new ClassLocalization('Szöveg', 'Szöveg'));
|
|
403
|
+
profValues.classLocalizations.set('Number', new ClassLocalization('Szám', 'Szám'));
|
|
404
|
+
profValues.classLocalizations.set('Select', new ClassLocalization('Kiválasztás', 'Kiválasztás'));
|
|
405
|
+
profValues.classLocalizations.set('TextArea', new ClassLocalization('Hosszú szöveg', 'Hosszú szöveg'));
|
|
406
|
+
profValues.classLocalizations.set('Date', new ClassLocalization('Dátum', 'Dátum'));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
profValues.classLocalizations.set('Dataset', new ClassLocalization('Dataset', 'A collection of files with metadata'));
|
|
410
|
+
profValues.classLocalizations.set('File', new ClassLocalization('File', 'Data file'));
|
|
411
|
+
}
|
|
412
|
+
const classes = describoProfile.classes;
|
|
413
|
+
for (const input of profValues.inputs) {
|
|
414
|
+
const isDeprecated = input[1].isDeprecated();
|
|
415
|
+
if (!isDeprecated) {
|
|
416
|
+
const allChildrenAreDeprecated = this.areAllChildrenDeprecated(input, profValues.inputs);
|
|
417
|
+
if (!allChildrenAreDeprecated) {
|
|
418
|
+
const className = input[0];
|
|
419
|
+
if (!classes[className]) {
|
|
420
|
+
classes[className] = JSON.parse(JSON.stringify(classTemplate));
|
|
421
|
+
}
|
|
422
|
+
const classJson = classes[className];
|
|
423
|
+
classJson.inputs.push(input[1].toJSON());
|
|
424
|
+
const classLoc = profValues.classLocalizations.get(className);
|
|
425
|
+
if (classLoc != null) {
|
|
426
|
+
// This is our custom localisation at class level
|
|
427
|
+
classJson.label = classLoc.label;
|
|
428
|
+
classJson.help = classLoc.help;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// This is the Describo supported way of localisation
|
|
434
|
+
const localisation = {};
|
|
435
|
+
profValues.classLocalizations.forEach((value, key) => {
|
|
436
|
+
localisation[key] = value.label;
|
|
437
|
+
});
|
|
438
|
+
describoProfile.localisation = localisation;
|
|
439
|
+
const enabledClassesSet = new Set();
|
|
440
|
+
profValues.inputs
|
|
441
|
+
.filter(pair => !pair[1].isDeprecated())
|
|
442
|
+
.forEach(pair => enabledClassesSet.add(pair[0]));
|
|
443
|
+
describoProfile.enabledClasses = Array.from(enabledClassesSet);
|
|
444
|
+
return JSON.stringify(describoProfile, null, 2);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Check if all children of an input are deprecated
|
|
448
|
+
*/
|
|
449
|
+
areAllChildrenDeprecated(input, inputs) {
|
|
450
|
+
if (input[0] === 'Dataset') {
|
|
451
|
+
const typeName = input[1].getName();
|
|
452
|
+
if (!typeName) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
const filtered = inputs.filter(pair => pair[0] === typeName);
|
|
456
|
+
return filtered.length > 0 && filtered.every(pair => pair[1].isDeprecated());
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Process template properties recursively
|
|
464
|
+
*/
|
|
465
|
+
processTemplate(cedarTemplate, processedDescriboProfileValues, parentName) {
|
|
466
|
+
const propertyNames = getStringList(cedarTemplate, '_ui.order');
|
|
467
|
+
for (const propertyName of propertyNames) {
|
|
468
|
+
// Note: cannot use getJsonObject here because the propertyName may contain ".", eg:
|
|
469
|
+
// coverage.Spectral.CentralWavelength, which would result in properties.coverage.Spectral.CentralWavelength
|
|
470
|
+
const properties = cedarTemplate.properties;
|
|
471
|
+
if (!properties || !properties[propertyName]) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const property = properties[propertyName];
|
|
475
|
+
const propertyType = property['@type'] ?? null;
|
|
476
|
+
// richtext type can not be used in Describo, leave it out from the profile
|
|
477
|
+
const inputType = getJsonElement(property, '_ui.inputType');
|
|
478
|
+
if (inputType && typeof inputType === 'string' && inputType === 'richtext') {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const contextProps = getJsonElement(cedarTemplate, 'properties.@context.properties');
|
|
482
|
+
if (!contextProps || !contextProps[propertyName] || !contextProps[propertyName].enum || !Array.isArray(contextProps[propertyName].enum) || contextProps[propertyName].enum.length === 0) {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
const inputId = contextProps[propertyName].enum[0];
|
|
486
|
+
if (propertyType != null) {
|
|
487
|
+
const actPropertyType = typeof propertyType === 'string' ? propertyType.substring(propertyType.lastIndexOf('/') + 1) : null;
|
|
488
|
+
if (!actPropertyType) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const ui = property._ui;
|
|
492
|
+
const isHidden = ui && ui.hidden === true;
|
|
493
|
+
if (!isHidden && (actPropertyType === 'TemplateField' || actPropertyType === 'StaticTemplateField')) {
|
|
494
|
+
const valueConstraints = property._valueConstraints;
|
|
495
|
+
const allowMultiple = (valueConstraints && valueConstraints.multipleChoice === true) ||
|
|
496
|
+
(property.minItems !== undefined || property.maxItems !== undefined);
|
|
497
|
+
this.processTemplateField(property, allowMultiple, inputId, processedDescriboProfileValues, parentName);
|
|
498
|
+
}
|
|
499
|
+
else if (actPropertyType === 'TemplateElement') {
|
|
500
|
+
const propertyLabels = getJsonObject(cedarTemplate, '_ui.propertyLabels');
|
|
501
|
+
this.processTemplateElement(property, processedDescriboProfileValues, false, inputId, parentName, propertyLabels);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
const actPropertyType = property.type;
|
|
506
|
+
if (actPropertyType === 'array') {
|
|
507
|
+
const propertyLabels = getJsonObject(cedarTemplate, '_ui.propertyLabels');
|
|
508
|
+
this.processArray(property, processedDescriboProfileValues, inputId, parentName, propertyLabels);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return processedDescriboProfileValues;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Process a template field
|
|
516
|
+
*/
|
|
517
|
+
processTemplateField(templateField, allowMultiple, inputId, processedDescriboProfileValues, parentName) {
|
|
518
|
+
const describoInput = new DescriboInput();
|
|
519
|
+
let fieldType = null;
|
|
520
|
+
const inputTypeElement = getJsonElement(templateField, '_ui.inputType');
|
|
521
|
+
if (inputTypeElement && typeof inputTypeElement === 'string') {
|
|
522
|
+
fieldType = inputTypeElement;
|
|
523
|
+
}
|
|
524
|
+
const externalVocab = hasExternalValues(templateField);
|
|
525
|
+
if (externalVocab) {
|
|
526
|
+
fieldType = 'list';
|
|
527
|
+
}
|
|
528
|
+
describoInput.setId(inputId);
|
|
529
|
+
// Replace the ":" with "." upon generating the Describo Profile from the CEDAR Template
|
|
530
|
+
const schemaName = templateField['schema:name'];
|
|
531
|
+
if (!schemaName || typeof schemaName !== 'string') {
|
|
532
|
+
return; // Skip if no schema name
|
|
533
|
+
}
|
|
534
|
+
describoInput.setName(schemaName.replace(':', '.'));
|
|
535
|
+
const label = this.getLocalizedLabel(templateField);
|
|
536
|
+
describoInput.setLabel(label);
|
|
537
|
+
const help = this.getLocalizedHelp(templateField);
|
|
538
|
+
describoInput.setHelp(help);
|
|
539
|
+
describoInput.setType(this.getDescriboType(fieldType));
|
|
540
|
+
// Special Select styles for checkbox and radio CEDAR types
|
|
541
|
+
if (fieldType === 'checkbox') {
|
|
542
|
+
describoInput.setStyle('checkbox');
|
|
543
|
+
}
|
|
544
|
+
else if (fieldType === 'radio') {
|
|
545
|
+
describoInput.setStyle('radio');
|
|
546
|
+
}
|
|
547
|
+
const requiredValue = getJsonElement(templateField, '_valueConstraints.requiredValue');
|
|
548
|
+
describoInput.setRequired(requiredValue === true);
|
|
549
|
+
const minValue = getJsonElement(templateField, '_valueConstraints.minValue');
|
|
550
|
+
describoInput.setMinValue(minValue != null && typeof minValue === 'number' ? Math.floor(minValue) : undefined);
|
|
551
|
+
const maxValue = getJsonElement(templateField, '_valueConstraints.maxValue');
|
|
552
|
+
describoInput.setMaxValue(maxValue != null && typeof maxValue === 'number' ? Math.floor(maxValue) : undefined);
|
|
553
|
+
const minLength = getJsonElement(templateField, '_valueConstraints.minLength');
|
|
554
|
+
describoInput.setMinLength(minLength != null && typeof minLength === 'number' ? Math.floor(minLength) : undefined);
|
|
555
|
+
const maxLength = getJsonElement(templateField, '_valueConstraints.maxLength');
|
|
556
|
+
describoInput.setMaxLength(maxLength != null && typeof maxLength === 'number' ? Math.floor(maxLength) : undefined);
|
|
557
|
+
const regex = getJsonElement(templateField, '_valueConstraints.regex');
|
|
558
|
+
describoInput.setRegex(regex != null && typeof regex === 'string' ? regex : undefined);
|
|
559
|
+
const placeholder = getJsonElement(templateField, '_arp.dataverse.watermark');
|
|
560
|
+
describoInput.setPlaceholder(placeholder != null && typeof placeholder === 'string' ? placeholder : undefined);
|
|
561
|
+
describoInput.setMultiple(allowMultiple);
|
|
562
|
+
describoInput.setDeprecated(isDeprecatedField(templateField));
|
|
563
|
+
let literalValues = [];
|
|
564
|
+
if (fieldType != null && (fieldType === 'list' || fieldType === 'radio' || fieldType === 'checkbox')) {
|
|
565
|
+
if (externalVocab) {
|
|
566
|
+
literalValues = getExternalVocabValues(templateField);
|
|
567
|
+
if (literalValues.length > 0) {
|
|
568
|
+
describoInput.setValues(literalValues);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
const jsonElement = getJsonElement(templateField, '_valueConstraints.literals');
|
|
573
|
+
const literals = jsonElement != null && Array.isArray(jsonElement) ? jsonElement : [];
|
|
574
|
+
literalValues = [];
|
|
575
|
+
literals.forEach((literal) => {
|
|
576
|
+
if (literal && typeof literal === 'object' && literal.label && typeof literal.label === 'string') {
|
|
577
|
+
literalValues.push(literal.label);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
if (literalValues.length > 0) {
|
|
582
|
+
describoInput.setValues(literalValues);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (fieldType === 'numeric') {
|
|
586
|
+
// minValue and maxValue always handled as an int, even for long, double and float numbers
|
|
587
|
+
const numMinValue = getJsonElement(templateField, '_valueConstraints.minValue');
|
|
588
|
+
describoInput.setMinValue(numMinValue != null && typeof numMinValue === 'number' ? Math.floor(numMinValue) : undefined);
|
|
589
|
+
const numMaxValue = getJsonElement(templateField, '_valueConstraints.maxValue');
|
|
590
|
+
describoInput.setMaxValue(numMaxValue != null && typeof numMaxValue === 'number' ? Math.floor(numMaxValue) : undefined);
|
|
591
|
+
const numberType = getJsonElement(templateField, '_valueConstraints.numberType');
|
|
592
|
+
if (numberType != null && typeof numberType === 'string') {
|
|
593
|
+
const cedarNumberType = this.cedarDescriboNumberTypes.get(numberType);
|
|
594
|
+
if (cedarNumberType) {
|
|
595
|
+
describoInput.setNumberType(cedarNumberType);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
if (fieldType === 'temporal') {
|
|
600
|
+
const temporalType = getJsonElement(templateField, '_valueConstraints.temporalType');
|
|
601
|
+
if (temporalType != null && typeof temporalType === 'string') {
|
|
602
|
+
const cedarDateType = this.cedarDescriboDateTypes.get(temporalType);
|
|
603
|
+
if (cedarDateType) {
|
|
604
|
+
describoInput.setType(cedarDateType);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// hard-coded regexes
|
|
609
|
+
if (fieldType === 'email' && describoInput.getRegex() == null) {
|
|
610
|
+
describoInput.setRegex('^((?!\\.)[\\w\\-_.]*[^.])(@\\w+(\\-?\\w+)*)(\\.\\w+(\\-?\\w+)*)*\\.[a-zA-Z]{2,}$');
|
|
611
|
+
}
|
|
612
|
+
if (fieldType === 'phone-number' && describoInput.getRegex() == null) {
|
|
613
|
+
describoInput.setRegex('(?:([+]\\d{1,4})[-.\\s]?)?(?:[(](\\d{1,3})[)][-.\\s]?)?(\\d{1,4})[-.\\s]?(\\d{1,4})[-.\\s]?(\\d{1,9})');
|
|
614
|
+
}
|
|
615
|
+
if (fieldType === 'textfield') {
|
|
616
|
+
const dateFormat = getJsonElement(templateField, '_arp.aroma.dateFormat');
|
|
617
|
+
if (dateFormat != null && typeof dateFormat === 'string') {
|
|
618
|
+
describoInput.setDateFormat([dateFormat]);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
processedDescriboProfileValues.inputs.push([parentName, describoInput]);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* "dataverseFile" is a special Template Element in CEDAR that is used to represent file relations
|
|
625
|
+
* this property needs to be handled differently
|
|
626
|
+
*/
|
|
627
|
+
processTemplateElement(templateElement, processedDescriboProfileValues, allowMultiple, inputId, parentName, propertyLabels) {
|
|
628
|
+
const describoInput = new DescriboInput();
|
|
629
|
+
const schemaName = templateElement['schema:name'];
|
|
630
|
+
if (!schemaName || typeof schemaName !== 'string') {
|
|
631
|
+
return; // Skip if no schema name
|
|
632
|
+
}
|
|
633
|
+
const elementNameReplaced = schemaName.replace(':', '.');
|
|
634
|
+
// Replace the ":" with "." upon generating the Describo Profile from the CEDAR Template
|
|
635
|
+
const schemaIdentifier = templateElement['schema:identifier'];
|
|
636
|
+
const type = schemaIdentifier && typeof schemaIdentifier === 'string' ? schemaIdentifier.replace(':', '.') : elementNameReplaced;
|
|
637
|
+
const actualType = type === 'dataverseFile' ? 'File' : type === 'dataverseDataset' ? 'Dataset' : elementNameReplaced;
|
|
638
|
+
describoInput.setId(inputId);
|
|
639
|
+
describoInput.setName(elementNameReplaced);
|
|
640
|
+
const label = this.getLocalizedLabel(templateElement);
|
|
641
|
+
describoInput.setLabel(label);
|
|
642
|
+
const help = this.getLocalizedHelp(templateElement);
|
|
643
|
+
describoInput.setHelp(help);
|
|
644
|
+
describoInput.setType([actualType]);
|
|
645
|
+
const requiredValue = getJsonElement(templateElement, '_valueConstraints.requiredValue');
|
|
646
|
+
describoInput.setRequired(requiredValue === true);
|
|
647
|
+
const allowsMultiple = allowMultiple || templateElement.minItems !== undefined || templateElement.maxItems !== undefined;
|
|
648
|
+
describoInput.setMultiple(allowsMultiple);
|
|
649
|
+
describoInput.setDeprecated(isDeprecatedField(templateElement));
|
|
650
|
+
processedDescriboProfileValues.classLocalizations.set(elementNameReplaced, new ClassLocalization(label, help ?? ''));
|
|
651
|
+
processedDescriboProfileValues.inputs.push([parentName, describoInput]);
|
|
652
|
+
this.processTemplate(templateElement, processedDescriboProfileValues, elementNameReplaced);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Process array type
|
|
656
|
+
*/
|
|
657
|
+
processArray(array, processedDescriboProfileValues, inputId, parentName, propertyLabels) {
|
|
658
|
+
const items = array.items;
|
|
659
|
+
if (!items) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
const inputType = getJsonElement(items, '_ui.inputType');
|
|
663
|
+
if (inputType != null && typeof inputType === 'string') {
|
|
664
|
+
this.processTemplateField(items, true, inputId, processedDescriboProfileValues, parentName);
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
this.processTemplateElement(items, processedDescriboProfileValues, true, inputId, parentName, propertyLabels);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Process profile metadata
|
|
672
|
+
*/
|
|
673
|
+
processProfileMetadata(cedarTemplate, describoProfile) {
|
|
674
|
+
let name = cedarTemplate['schema:name'];
|
|
675
|
+
if (!name || typeof name !== 'string') {
|
|
676
|
+
name = 'Untitled';
|
|
677
|
+
}
|
|
678
|
+
if (this.language === 'hu') {
|
|
679
|
+
const hunName = cedarTemplate.hunName;
|
|
680
|
+
if (hunName && typeof hunName === 'string') {
|
|
681
|
+
name = hunName;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
describoProfile.metadata.name = name;
|
|
685
|
+
let desc = cedarTemplate['schema:description'];
|
|
686
|
+
if (!desc || typeof desc !== 'string') {
|
|
687
|
+
desc = '';
|
|
688
|
+
}
|
|
689
|
+
if (this.language === 'hu') {
|
|
690
|
+
const hunDescription = cedarTemplate.hunDescription;
|
|
691
|
+
if (hunDescription && typeof hunDescription === 'string') {
|
|
692
|
+
desc = hunDescription;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
describoProfile.metadata.description = desc;
|
|
696
|
+
}
|
|
697
|
+
getDescriboType(arg) {
|
|
698
|
+
if (arg == null) {
|
|
699
|
+
return undefined;
|
|
700
|
+
}
|
|
701
|
+
// If it's an object, treat it as templateField
|
|
702
|
+
if (typeof arg === 'object') {
|
|
703
|
+
const fieldType = getJsonElement(arg, '_ui.inputType');
|
|
704
|
+
if (fieldType != null && typeof fieldType === 'string' && this.cedarDescriboFieldTypes.has(fieldType)) {
|
|
705
|
+
return this.cedarDescriboFieldTypes.get(fieldType);
|
|
706
|
+
}
|
|
707
|
+
return undefined;
|
|
708
|
+
}
|
|
709
|
+
// If it's a string, treat it as cedarFieldType
|
|
710
|
+
if (typeof arg === 'string') {
|
|
711
|
+
return this.cedarDescriboFieldTypes.get(arg);
|
|
712
|
+
}
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Get localized label
|
|
717
|
+
*/
|
|
718
|
+
getLocalizedLabel(obj) {
|
|
719
|
+
let label = '';
|
|
720
|
+
let engLabel = obj['schema:name'];
|
|
721
|
+
if (!engLabel || typeof engLabel !== 'string') {
|
|
722
|
+
engLabel = '';
|
|
723
|
+
}
|
|
724
|
+
// Absolute fallback: the field name
|
|
725
|
+
const prefLabel = obj['skos:prefLabel'];
|
|
726
|
+
// If we have an english name in skos:prefLabel, use that
|
|
727
|
+
if (prefLabel != null && typeof prefLabel === 'string' && prefLabel.length > 0) {
|
|
728
|
+
engLabel = prefLabel;
|
|
729
|
+
}
|
|
730
|
+
// If we have an hunLabel, use that for hunLabel, otherwise fall back to engLabel
|
|
731
|
+
if (this.language === 'hu') {
|
|
732
|
+
const hunLabel = obj.hunLabel;
|
|
733
|
+
if (hunLabel == null || typeof hunLabel !== 'string' || hunLabel.length === 0) {
|
|
734
|
+
label = engLabel + ' (magyarul)';
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
label = hunLabel;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
label = engLabel;
|
|
742
|
+
}
|
|
743
|
+
return label;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Get localized help text
|
|
747
|
+
*/
|
|
748
|
+
getLocalizedHelp(obj) {
|
|
749
|
+
let help = undefined;
|
|
750
|
+
if (this.language === 'hu') {
|
|
751
|
+
const hunDescription = obj.hunDescription;
|
|
752
|
+
if (hunDescription != null && typeof hunDescription === 'string') {
|
|
753
|
+
help = hunDescription;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
const schemaDescription = obj['schema:description'];
|
|
758
|
+
if (schemaDescription != null && typeof schemaDescription === 'string') {
|
|
759
|
+
help = schemaDescription;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return help;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
//# sourceMappingURL=cedar-converter.js.map
|