1
1
/* eslint-disable no-underscore-dangle */
2
-
3
2
const R = require ( 'ramda' ) ;
3
+
4
4
const {
5
- ArrayElement,
6
- ObjectElement,
7
5
StringElement,
8
6
BooleanElement,
9
7
NumberElement,
10
8
NullElement,
11
9
} = require ( 'minim' ) ;
12
10
13
- const EnumElement = require ( './elements/Enum' ) ;
11
+ /**
12
+ * Get element attribute
13
+ * @param {element } e - element - element
14
+ * @param {string } attribute
15
+ * @return {element }
16
+ */
17
+ const getAttribute = ( e , attribute ) => e . _attributes && e . attributes . get ( attribute ) ;
14
18
15
19
/**
16
20
* Check if element has a typeAttribute
@@ -19,7 +23,7 @@ const EnumElement = require('./elements/Enum');
19
23
* @return {boolean }
20
24
*/
21
25
function hasTypeAttribute ( e , attribute ) {
22
- const typeAttributes = e . _attributes && e . attributes . get ( 'typeAttributes' ) ;
26
+ const typeAttributes = getAttribute ( e , 'typeAttributes' ) ;
23
27
if ( typeAttributes ) {
24
28
return typeAttributes . includes ( attribute ) ;
25
29
}
@@ -55,33 +59,85 @@ const isNullable = e => hasTypeAttribute(e, 'nullable');
55
59
*/
56
60
const isOptional = e => hasTypeAttribute ( e , 'optional' ) ;
57
61
62
+ const baseTypes = new Set ( [
63
+ 'boolean' ,
64
+ 'string' ,
65
+ 'number' ,
66
+ 'array' ,
67
+ 'object' ,
68
+ 'enum' ,
69
+ 'null' ,
70
+ 'member' ,
71
+ 'select' ,
72
+ 'option' ,
73
+ 'extend' ,
74
+ 'ref' ,
75
+ 'link' ,
76
+ ] ) ;
77
+ /**
78
+ * Check if element is one of the base types
79
+ * @param {element } e - element
80
+ * @return {boolean }
81
+ */
82
+ const isBaseType = e => baseTypes . has ( e && e . element ) ;
83
+
84
+ /**
85
+ * Get the element type - prefer a base type, if found
86
+ * @param {element } e - element
87
+ * @param {object= } elements - object map of elements to look for inherited type
88
+ * @return {string }
89
+ */
90
+ const getType = ( e , elements ) => {
91
+ if ( e === undefined ) {
92
+ return undefined ;
93
+ }
94
+ if ( isBaseType ( e ) ) {
95
+ return e . element ;
96
+ }
97
+
98
+ const inheritedType = e . element && elements && elements [ e . element ] ;
99
+ if ( inheritedType !== undefined ) {
100
+ return getType ( inheritedType , elements ) ;
101
+ }
102
+
103
+ return e && e . element ;
104
+ } ;
105
+
106
+ const primitives = new Set ( [ 'string' , 'number' , 'boolean' , 'null' ] ) ;
58
107
/**
59
108
* Check if the element is of a primitive type
60
109
* @param {element } e - element
110
+ * @param {object= } elements - object map of elements to look for inherited type
61
111
* @return {boolean }
62
112
*/
63
- const isPrimitive = e => ( e instanceof StringElement ) || ( e instanceof NumberElement ) || ( e instanceof BooleanElement ) ;
113
+ const isPrimitive = ( e , elements ) => {
114
+ const type = getType ( e , elements ) ;
115
+ return primitives . has ( String ( type ) ) ;
116
+ } ;
64
117
65
118
/**
66
119
* Check if the element type is Enum
67
120
* @param {element } e - element
121
+ * @param {object= } elements - object map of elements to look for inherited type
68
122
* @return {boolean }
69
123
*/
70
- const isEnum = e => e instanceof EnumElement ;
124
+ const isEnum = ( e , elements ) => getType ( e , elements ) === 'enum' ;
71
125
72
126
/**
73
127
* Check if the element type is Array
74
128
* @param {element } e - element
129
+ * @param {object= } elements - object map of elements to look for inherited type
75
130
* @return {boolean }
76
131
*/
77
- const isArray = e => e instanceof ArrayElement ;
132
+ const isArray = ( e , elements ) => getType ( e , elements ) === 'array' ;
78
133
79
134
/**
80
135
* Check if the element type is Object
81
136
* @param {element } e - element
137
+ * @param {object= } elements - object map of elements to look for inherited type
82
138
* @return {boolean }
83
139
*/
84
- const isObject = e => e instanceof ObjectElement ;
140
+ const isObject = ( e , elements ) => getType ( e , elements ) === 'object' ;
85
141
86
142
/**
87
143
* Get the element default
@@ -149,23 +205,27 @@ const hasNoValue = R.complement(hasValue);
149
205
/**
150
206
* Check if the element is of a primitive type and has no value (content/sample/default)
151
207
* @param {element } e - element
208
+ * @param {object= } elements - object map of elements to look for inherited type
152
209
* @return {boolean }
153
210
*/
154
- const isNoValuePrimitive = R . both ( isPrimitive , hasNoValue ) ;
211
+ const isNoValuePrimitive = ( e , elements ) => isPrimitive ( e , elements ) && hasNoValue ( e ) ;
155
212
156
213
/**
157
214
* Check if the element type is array and is not empty
158
215
* @param {element } e - element
216
+ * @param {object= } elements - object map of elements to look for inherited type
159
217
* @return {boolean }
160
218
*/
161
- const isNonEmptyArray = e => isArray ( e ) && e . content && ! e . isEmpty ;
219
+ const isNonEmptyArray = ( e , elements ) => isArray ( e , elements ) && e . content !== undefined && ! e . isEmpty ;
162
220
163
221
/**
164
222
* Check if the element type is array and has only primitive elements with no value
165
223
* @param {element } e - element
224
+ * @param {object= } elements - object map of elements to look for inherited type
166
225
* @return {boolean }
167
226
*/
168
- const isEmptyArray = e => isArray ( e ) && e . content . every ( isNoValuePrimitive ) ;
227
+ const isEmptyArray = ( e , elements ) => isArray ( e , elements )
228
+ && ( e . content === undefined || e . content . every ( member => isNoValuePrimitive ( member , elements ) ) ) ;
169
229
170
230
/**
171
231
* Check if the element type is 'ref'
@@ -177,10 +237,12 @@ const isRef = e => e && e.element === 'ref';
177
237
/**
178
238
* Check if the element type is object and has all property values undefined
179
239
* @param {element } e - element
240
+ * @param {object= } elements - object map of elements to look for inherited type
180
241
* @return {boolean }
181
242
*/
182
- const isObjectWithUndefinedValues = e => isObject ( e )
183
- && e . content . every ( prop => prop . value === undefined || prop . value . content === undefined ) ;
243
+ const isObjectWithUndefinedValues = ( e , elements ) => isObject ( e , elements ) && e . content . every (
244
+ prop => prop . value === undefined || prop . value . content === undefined
245
+ ) ;
184
246
185
247
/**
186
248
* Get a trivial value, to fill the unset, according to the element type
@@ -207,6 +269,93 @@ function trivialValue(e) {
207
269
return undefined ;
208
270
}
209
271
272
+ /**
273
+ * Get a key for the element member
274
+ * This is used to identify each member on the Map, allowing overrides in Objects
275
+ * @param {element } e - element
276
+ * @param {object= } elements - object map of elements to look for inherited type
277
+ * @return {(string|number|object|null) } - Map key
278
+ */
279
+ function getMemberKey ( e , elements ) {
280
+ if ( isPrimitive ( e , elements ) ) {
281
+ // return unique identifier
282
+ return Math . random ( ) ;
283
+ }
284
+
285
+ const key = e && e . content && e . content . key && e . content . key . toValue ( ) ;
286
+ const content = e && e . content ;
287
+ const type = e . element ;
288
+
289
+ return key || content || type ;
290
+ }
291
+
292
+ /**
293
+ * Get an Array with the element members
294
+ * @param {element } e - element
295
+ * @param {object= } elements - object map of elements to look for inherited type
296
+ * @return {element[] } - element members
297
+ */
298
+ function getMembers ( e , elements ) {
299
+ if ( e === undefined ) {
300
+ return [ ] ;
301
+ }
302
+
303
+ if ( isEnum ( e , elements ) ) {
304
+ const enumerations = getAttribute ( e , 'enumerations' ) ;
305
+ if ( enumerations && enumerations . content !== undefined ) {
306
+ return enumerations . content ;
307
+ }
308
+ }
309
+
310
+ if ( Array . isArray ( e . content ) ) {
311
+ return e . content ;
312
+ }
313
+
314
+ return [ e ] ;
315
+ }
316
+
317
+ /**
318
+ * Get a Map with all the element members, including references
319
+ * @param {element } e - element
320
+ * @param {object= } elements - object map of elements to look for inherited type
321
+ * @return {Map<element> } - element members
322
+ */
323
+ function getAllMembersMap ( e , elements ) {
324
+ if ( e === undefined ) {
325
+ return new Map ( ) ;
326
+ }
327
+
328
+ const typeElement = elements && elements [ e . element ] ;
329
+ const typeMembersMap = getAllMembersMap ( typeElement , elements ) ;
330
+ const ownMembers = getMembers ( e , elements ) ;
331
+ const ownMembersMap = new Map ( ) ;
332
+
333
+ ownMembers . forEach ( ( member ) => {
334
+ if ( isRef ( member ) ) {
335
+ const refElement = elements && elements [ member . content ] ;
336
+ const refMembersMap = getAllMembersMap ( refElement , elements ) ;
337
+ refMembersMap . forEach ( ( refMember ) => {
338
+ ownMembersMap . set ( getMemberKey ( refMember , elements ) , refMember ) ;
339
+ } ) ;
340
+ } else {
341
+ ownMembersMap . set ( getMemberKey ( member , elements ) , member ) ;
342
+ }
343
+ } ) ;
344
+ return new Map ( [ ...typeMembersMap , ...ownMembersMap ] ) ;
345
+ }
346
+
347
+ /**
348
+ * Get an Array with all the element members, including references
349
+ * @param {element } e - element
350
+ * @param {object= } elements - object map of elements to look for inherited type
351
+ * @return {element[] } - element members
352
+ */
353
+ function getStructureMembers ( e , elements ) {
354
+ const membersMap = getAllMembersMap ( e , elements ) ;
355
+
356
+ return Array . from ( membersMap . values ( ) ) ;
357
+ }
358
+
210
359
module . exports = {
211
360
isFixed,
212
361
isRequired,
@@ -223,4 +372,5 @@ module.exports = {
223
372
isRef,
224
373
isObjectWithUndefinedValues,
225
374
trivialValue,
375
+ getStructureMembers,
226
376
} ;
0 commit comments