[SDC-29] Amdocs OnBoard 1707 initial commit.
[sdc.git] / openecomp-ui / src / nfvo-utils / json / JSONSchema.js
1 /*!
2  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 // import Ajv from 'ajv';
17 import cloneDeep from 'lodash/cloneDeep.js';
18 import JSONPointer from './JSONPointer.js';
19
20 export default class JSONSchema {
21
22         setSchema(schema) {
23                 this._schema = schema;
24                 this._fragmentsCache = new Map();
25                 // this._ajv = new Ajv({
26                 //      useDefaults: true,
27                 //      coerceTypes: true
28                 // });
29                 // this._validate = this._ajv.compile(schema);
30         }
31
32         processData(data) {
33                 data = cloneDeep(data);
34                 // this._validate(data);
35                 return data;
36         }
37
38         // array of names of validation functions
39         setSupportedValidationFunctions(supportedValidationFunctions) {
40                 this._supportedValidationFunctions = supportedValidationFunctions;
41         }
42
43         /* FYI - I was going to support "required" but then found out that server never sends it in its schema (it was a business decision. so leaving the code commented for now */
44         flattenSchema(supportedValidationFunctions) {
45                 if (supportedValidationFunctions) { this.setSupportedValidationFunctions(supportedValidationFunctions); }
46                 let genericFieldInfo = {};
47                 if (this._schema && this._schema.properties) {
48                         this.travelProperties(this._schema.properties, genericFieldInfo/*, this._schema.required*/);
49                 }
50                 return {genericFieldInfo};
51         }
52
53         extractGenericFieldInfo(item) {
54                 let validationsArr = [];
55                 let additionalInfo = { isValid: true, errorText: ''};
56                 for (let value in item) {
57                         if (this._supportedValidationFunctions.includes(value)) {
58                                 let validationItem = this.extractValidations(item, value);
59                                 validationsArr[validationsArr.length] = validationItem;
60                         } else {
61                                 let enumResult = this.extractEnum(item, value);
62                                 if (enumResult !== null) {
63                                         additionalInfo.enum = enumResult;
64                                 }
65                                 else {
66                                         additionalInfo[value] = item[value];
67                                 }
68                                 /*if (required.includes (property)) {
69                                  additionalInfo[value].isRequired = true ;
70                                  }*/
71                         }
72                 }
73
74                 additionalInfo.validations = validationsArr;
75                 return additionalInfo;
76         }
77
78         extractValidations(item, value) {
79                 let validationItem;
80                 let data = item[value];
81                 if (value === 'maximum') {
82                         if (item.exclusiveMaximum) {
83                                 value = 'maximumExclusive';
84                         }
85                 }
86                 if (value === 'minimum') {
87                         if (item.exclusiveMinimum) {
88                                 value = 'minimumExclusive';
89                         }
90                 }
91                 validationItem = {type: value, data: data};
92                 return validationItem;
93         }
94
95         extractEnum(item, value) {
96                 let enumResult = null;
97                 if (value === 'type' && item[value] === 'array') {
98                         let items = item.items;
99                         if (items && items.enum && items.enum.length > 0) {
100                                 let values = items.enum
101                                         .filter(value => value)
102                                         .map(value => ({enum: value, title: value}));
103                                 enumResult = values;
104                         }
105                 }
106                 else if (value === 'enum') {
107                         let items = item[value];
108                         if (items && items.length > 0) {
109                                 let values = items
110                                         .filter(value => value)
111                                         .map(value => ({enum: value, title: value}));
112                                 enumResult = values;
113                         }
114                 }
115                 return enumResult;
116         }
117
118         travelProperties(properties, genericFieldDefs, /*required = [],*/ pointer = ''){
119                 let newPointer = pointer;
120                 for (let property in properties) {
121                         newPointer = newPointer ? newPointer + '/' + property : property;
122                         if (properties[property].properties) {
123                                 this.travelProperties(properties[property].properties, genericFieldDefs /*, properties[property].required*/, newPointer);
124                         }
125                         else if (properties[property].$ref){
126                                 let fragment = this._getSchemaFragmentByRef(properties[property].$ref);
127                                 if (fragment.properties) {
128                                         this.travelProperties(fragment.properties, genericFieldDefs /*, properties[property].required*/, newPointer);
129                                 } else {
130                                         genericFieldDefs[newPointer] = this.extractGenericFieldInfo(fragment.properties);
131                                 }
132                         }
133                         else {
134                                 genericFieldDefs[newPointer] = this.extractGenericFieldInfo(properties[property]);
135                         }
136                         newPointer = pointer;
137                 }
138         }
139
140         getTitle(pointer) {
141                 return this._getSchemaFragment(pointer).title;
142         }
143
144         exists(pointer) {
145                 const fragment = this._getSchemaFragment(pointer);
146                 return !!fragment;
147         }
148
149         getDefault(pointer) {
150                 const fragment = this._getSchemaFragment(pointer);
151                 return fragment && fragment.default;
152         }
153
154         getEnum(pointer) {
155                 const fragment = this._getSchemaFragment(pointer);
156                 return fragment && (fragment.type === 'array' ? fragment.items.enum : fragment.enum);
157         }
158
159         isRequired(pointer) {
160                 const parentPointer = JSONPointer.extractParentPointer(pointer);
161                 const lastPart = JSONPointer.extractLastPart(pointer);
162                 let parentFragment = this._getSchemaFragment(parentPointer);
163                 return parentFragment && parentFragment.required && parentFragment.required.includes(lastPart);
164         }
165
166         isNumber(pointer) {
167                 const fragment = this._getSchemaFragment(pointer);
168                 return fragment && fragment.type === 'number';
169         }
170
171         getMaxValue(pointer) {
172                 const fragment = this._getSchemaFragment(pointer);
173                 return fragment && fragment.exclusiveMaximum ? fragment.maximum - 1 : fragment.maximum;
174         }
175
176         getMinValue(pointer) {
177                 const fragment = this._getSchemaFragment(pointer);
178                 return fragment && fragment.exclusiveMinimum ? fragment.minimum : fragment.minimum;
179         }
180
181         isString(pointer) {
182                 const fragment = this._getSchemaFragment(pointer);
183                 return fragment && fragment.type === 'string';
184         }
185
186         getPattern(pointer) {
187                 const fragment = this._getSchemaFragment(pointer);
188                 return fragment && fragment.pattern;
189         }
190
191         getMaxLength(pointer) {
192                 const fragment = this._getSchemaFragment(pointer);
193                 return fragment && fragment.maxLength;
194         }
195
196         getMinLength(pointer) {
197                 const fragment = this._getSchemaFragment(pointer);
198                 return fragment && fragment.minLength;
199         }
200
201         isArray(pointer) {
202                 const fragment = this._getSchemaFragment(pointer);
203                 return fragment && fragment.type === 'array';
204         }
205
206         _getSchemaFragment(pointer) {
207                 if (this._fragmentsCache.has(pointer)) {
208                         return this._fragmentsCache.get(pointer);
209                 }
210
211                 let parts = JSONPointer.extractParts(pointer);
212
213                 let fragment = parts.reduce((fragment, part) => {
214                         if (fragment === undefined) {
215                                 return undefined;
216                         }
217
218                         if (fragment.$ref) {
219                                 fragment = this._getSchemaFragmentByRef(fragment.$ref);
220                         }
221
222                         switch (fragment.type) {
223                                 case 'object':
224                                         return fragment.properties && fragment.properties[part];
225
226                                 case 'array':
227                                         return fragment.enum && fragment.enum[part];
228
229                                 default:
230                                         // throw new Error(`Incorrect/unsupported JSONPointer "${pointer}" from "${part}"`);
231                                         return undefined;
232                         }
233                 }, this._schema);
234
235                 while(fragment && fragment.$ref) {
236                         fragment = this._getSchemaFragmentByRef(fragment.$ref);
237                 }
238
239                 this._fragmentsCache.set(pointer, fragment);
240                 return fragment;
241         }
242
243         _getSchemaFragmentByRef($ref) {
244                 let pointer = $ref.substr(1);
245                 return JSONPointer.getValue(this._schema, pointer);
246                 // let fragmentAjv = new Ajv();
247                 // fragmentAjv.addSchema(this._schema);
248                 // let compiledFragment = fragmentAjv.compile({$ref});
249                 // let fragment = compiledFragment.refVal[compiledFragment.refs[$ref]];
250                 // return fragment;
251         }
252 };