blob: 3b3a9bf7b4b330284c1ad4baa5ed7bf3ea3bea4c [file] [log] [blame]
AviZi280f8012017-06-09 02:39:56 +03001/*!
Michael Landoefa037d2017-02-19 12:57:33 +02002 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
AviZi280f8012017-06-09 02:39:56 +03003 *
Michael Landoefa037d2017-02-19 12:57:33 +02004 * 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
AviZi280f8012017-06-09 02:39:56 +03007 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
Michael Landoefa037d2017-02-19 12:57:33 +020010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
AviZi280f8012017-06-09 02:39:56 +030012 * 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.
Michael Landoefa037d2017-02-19 12:57:33 +020015 */
Michael Landoefa037d2017-02-19 12:57:33 +020016// import Ajv from 'ajv';
17import cloneDeep from 'lodash/cloneDeep.js';
18import JSONPointer from './JSONPointer.js';
19
20export 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
AviZi280f8012017-06-09 02:39:56 +030038 // 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
Michael Landoefa037d2017-02-19 12:57:33 +0200140 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);
AviZi280f8012017-06-09 02:39:56 +0300173 return fragment && fragment.exclusiveMaximum ? fragment.maximum - 1 : fragment.maximum;
Michael Landoefa037d2017-02-19 12:57:33 +0200174 }
175
176 getMinValue(pointer) {
177 const fragment = this._getSchemaFragment(pointer);
AviZi280f8012017-06-09 02:39:56 +0300178 return fragment && fragment.exclusiveMinimum ? fragment.minimum : fragment.minimum;
Michael Landoefa037d2017-02-19 12:57:33 +0200179 }
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};