Add code for data format webtool
[dcaegen2/platform/cli.git] / dcaedftool / src / app / df-jsoninput.component.ts
1 // org.onap.dcae\r
2 // ============LICENSE_START====================================================\r
3 // Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.\r
4 // =============================================================================\r
5 // Licensed under the Apache License, Version 2.0 (the "License");\r
6 // you may not use this file except in compliance with the License.\r
7 // You may obtain a copy of the License at\r
8 //\r
9 //     http://www.apache.org/licenses/LICENSE-2.0\r
10 //\r
11 // Unless required by applicable law or agreed to in writing, software\r
12 // distributed under the License is distributed on an "AS IS" BASIS,\r
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14 // See the License for the specific language governing permissions and\r
15 // limitations under the License.\r
16 // ============LICENSE_END======================================================\r
17 //\r
18 // ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
19 import { Component, Input, OnInit, OnChanges} from '@angular/core';\r
20 import { MdToolbarModule, MdButton, MdInputModule, MdSelectModule} from '@angular/material';\r
21 import {ValidateMetaSchemaService} from './validate-metaschema.service';\r
22 import {ValidateJSONService} from './validate-json.service';\r
23 import {MetaSchemaService} from './metaschema.service';\r
24 import * as Ajv from 'ajv';\r
25 \r
26 @Component({\r
27   selector: 'app-df-jsoninput',\r
28   templateUrl: './df-jsoninput.component.html',\r
29   styleUrls: [ './df-jsoninput.component.css']\r
30 })\r
31 export class DFJSONInputComponent implements OnInit /*, OnChanges */ {\r
32 \r
33   public dfschema = '';\r
34   private jsonTestObject: any;\r
35   private validJSON = false;\r
36   public metaDisplay = false;\r
37   public metaButton = 'Display MetaSchema';\r
38   public schemaMsg: string;\r
39   public schemaErrMsgs: string[] = [];\r
40   private ajvService: any;\r
41   private hideMeta = 'Hide MetaSchema';\r
42   private displayMeta = 'Display Metaschema';\r
43   private schemaValidate: Object;\r
44   private validateMetaSchema: ValidateMetaSchemaService;\r
45   private jsonValidate: ValidateJSONService;\r
46   private metaSchema: MetaSchemaService;\r
47   private validSchema = false;\r
48   public dfmetaschema: string;\r
49   public dfjson: string;\r
50   public jsonMsg: string;\r
51   public jsonErrMsgs: string[] = [];\r
52 \r
53   constructor (validateMetaSchemaService: ValidateMetaSchemaService, validateJSONService: ValidateJSONService, metaSchemaService: MetaSchemaService) {\r
54       this.validateMetaSchema = validateMetaSchemaService;\r
55       this.metaSchema = metaSchemaService;\r
56       this.dfmetaschema = this.metaSchema.currentMetaSchemaFormatted();\r
57       this.jsonValidate = validateJSONService;\r
58   }\r
59 \r
60 \r
61   ngOnInit(): void {\r
62   }\r
63 \r
64   toggleMetaSchema(): void {\r
65     this.metaDisplay = !this.metaDisplay;\r
66     if (this.metaDisplay === true) {\r
67       this.metaButton = this.hideMeta;\r
68     } else {\r
69       this.metaButton = this.displayMeta;\r
70     }\r
71   }\r
72   doDFSchemaChange(ev: any) {\r
73     this.schemaMsg = '';\r
74     this.schemaErrMsgs = [];\r
75     this.validSchema = false;\r
76     this.dfschema = ev.target.value;\r
77     if (this.dfschema.length == 0) {\r
78       if (this.validJSON) {\r
79         this.jsonMsg = 'Enter a Valid Schema';\r
80         this.jsonErrMsgs = [];\r
81       }\r
82       return;\r
83     }\r
84     if (this.jsonValidate.validate(this.dfschema) === false) {\r
85       // assumes simple message - TBD???\r
86       this.schemaMsg = this.jsonValidate.validateMsgs();\r
87       if (this.validJSON) {\r
88         this.jsonMsg = 'Enter a valid Schema';\r
89         this.jsonErrMsgs = [];\r
90       }\r
91       return;\r
92     }\r
93     const pschema = JSON.parse(this.dfschema);\r
94     if (!pschema.hasOwnProperty('jsonschema')) {\r
95       this.schemaMsg = 'Invalid Schema - must specify jsonschema';\r
96       if (this.validJSON) {\r
97         this.jsonMsg = 'Enter a valid Schema';\r
98         this.jsonErrMsgs = [];\r
99       }\r
100       return;\r
101     }\r
102     const jsonSchema = pschema.jsonschema;\r
103     if (jsonSchema.hasOwnProperty('$schema')) {\r
104       try {\r
105         if (!(jsonSchema.$schema === 'http://json-schema.org/draft-04/schema#')  ) {\r
106           this.schemaMsg = 'Invalid JSON Schema Data Format -  jsonschema$schema version must be 04';\r
107           if (this.validJSON) {\r
108             this.jsonMsg = 'Enter a Valid Schema';\r
109             this.jsonErrMsgs = [];\r
110           }\r
111           return;\r
112         }\r
113       } catch(schemaVersionErr) {\r
114          this.schemaMsg = 'Invalid JSON Schema Data Format -  jsonschema$schema version must be 04';\r
115          if (this.validJSON) {\r
116            this.jsonMsg = 'Enter a Valid Schema';\r
117            this.jsonErrMsgs = [];\r
118          }\r
119          return;\r
120       }\r
121     } else {\r
122        this.schemaMsg = 'Invalid JSON Schema Data Format -  jsonschema$schema must specified';\r
123        if (this.validJSON) {\r
124           this.jsonMsg = 'Enter a Valid Schema';\r
125           this.jsonErrMsgs = [];\r
126        }\r
127        return;\r
128     }\r
129     if (this.validateMetaSchema.validate(this.dfschema) === false) {\r
130       this.schemaMsg = 'Invalid Data Format Schema';\r
131       this.schemaErrMsgs = this.validateMetaSchema.validateMsgs();\r
132       if (this.validJSON) {\r
133         this.jsonMsg = 'Enter a valid Schema';\r
134         this.jsonErrMsgs = [];\r
135       }\r
136     } else {\r
137       this.schemaMsg = 'Valid Data Format Schema';\r
138       this.validSchema = true;\r
139       if (this.validJSON ) {\r
140         this.validateJSON();\r
141       }\r
142     }\r
143   }\r
144 \r
145  // no reuse - so no service\r
146  validateJSON() {\r
147       this.jsonErrMsgs = [];\r
148       this.jsonMsg = '';\r
149       this.validJSON = false;\r
150       if (this.dfjson.length == 0) {\r
151         return;\r
152       }\r
153       if (this.jsonValidate.validate(this.dfjson) === false) {\r
154         this.jsonMsg = this.jsonValidate.validateMsgs();\r
155         this.jsonErrMsgs = [];\r
156         return;\r
157       }\r
158       this.validJSON = true;\r
159       if (!this.validSchema) {\r
160         this.jsonMsg = 'Enter a Valid Schema';\r
161         this.jsonErrMsgs = [];\r
162         return;\r
163       }\r
164       // check for jsonschema in Schema file and validate based on version\r
165       const valpschema = JSON.parse(this.dfschema);\r
166       const valjsonSchema = valpschema.jsonschema;\r
167       const schemaVersion = valjsonSchema.$schema;\r
168 \r
169       try {\r
170         if (schemaVersion === 'http://json-schema.org/draft-04/schema#') {\r
171           this.ajvService = new Ajv({\r
172             meta: false, // optional, to prevent adding draft-06 meta-schema\r
173             extendRefs: true, // optional, current default is to 'fail', spec behaviour is to 'ignore'\r
174             allErrors:        true,\r
175             unknownFormats: 'ignore'  // optional, current default is true (fail)\r
176         });\r
177         // change this to http get at some point TBD\r
178         const schemav4: any = {    'id': 'http://json-schema.org/draft-04/schema#',    '$schema': 'http://json-schema.org/draft-04/schema#',    'description': 'Core schema meta-schema',    'definitions': {        'schemaArray': {            'type': 'array',            'minItems': 1,            'items': { '$ref': '#' }   },        'positiveInteger': {  'type': 'integer',            'minimum': 0        },        'positiveIntegerDefault0': {            'allOf': [ { '$ref': '#/definitions/positiveInteger' }, { 'default': 0 } ]        },        'simpleTypes': {            'enum': [ 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string' ]        },        'stringArray': {            'type': 'array',            'items': { 'type': 'string' },            'minItems': 1,            'uniqueItems': true        }    },    'type': 'object',    'properties': {        'id': {            'type': 'string',            'format': 'uri'        },        '$schema': {            'type': 'string',            'format': 'uri'        },        'title': {            'type': 'string'        },        'description': {            'type': 'string'        },        'default': {},        'multipleOf': {            'type': 'number',            'minimum': 0,            'exclusiveMinimum': true        },        'maximum': {            'type': 'number'        },        'exclusiveMaximum': {            'type': 'boolean',            'default': false        },        'minimum': {            'type': 'number'        },        'exclusiveMinimum': {            'type': 'boolean',            'default': false        },        'maxLength': { '$ref': '#/definitions/positiveInteger' },        'minLength': { '$ref': '#/definitions/positiveIntegerDefault0' },        'pattern': {            'type': 'string',            'format': 'regex'        },        'additionalItems': {            'anyOf': [                { 'type': 'boolean' },                { '$ref': '#' }            ],            'default': {}        },        'items': {            'anyOf': [                { '$ref': '#' },                { '$ref': '#/definitions/schemaArray' }            ],            'default': {}        },        'maxItems': { '$ref': '#/definitions/positiveInteger' },        'minItems': { '$ref': '#/definitions/positiveIntegerDefault0' },        'uniqueItems': {            'type': 'boolean',            'default': false        },        'maxProperties': { '$ref': '#/definitions/positiveInteger' },        'minProperties': { '$ref': '#/definitions/positiveIntegerDefault0' },        'required': { '$ref': '#/definitions/stringArray' },        'additionalProperties': {            'anyOf': [                { 'type': 'boolean' },                { '$ref': '#' }            ],            'default': {}        },        'definitions': {            'type': 'object',            'additionalProperties': { '$ref': '#' },            'default': {}        },        'properties': {            'type': 'object',            'additionalProperties': { '$ref': '#' },            'default': {}        },        'patternProperties': {            'type': 'object',            'additionalProperties': { '$ref': '#' },            'default': {}        },        'dependencies': {            'type': 'object',            'additionalProperties': {                'anyOf': [                    { '$ref': '#' },                    { '$ref': '#/definitions/stringArray' }                ]            }        },        'enum': {            'type': 'array',            'minItems': 1,            'uniqueItems': true        },        'type': {            'anyOf': [                { '$ref': '#/definitions/simpleTypes' },                {                    'type': 'array',                    'items': { '$ref': '#/definitions/simpleTypes' },                    'minItems': 1,                    'uniqueItems': true                }            ]        },        'allOf': { '$ref': '#/definitions/schemaArray' },        'anyOf': { '$ref': '#/definitions/schemaArray' },        'oneOf': { '$ref': '#/definitions/schemaArray' },        'not': { '$ref': '#' }    },    'dependencies': {        'exclusiveMaximum': [ 'maximum' ],        'exclusiveMinimum': [ 'minimum' ]    },    'default': {}}\r
179 \r
180         const metaSchema = schemav4;\r
181 \r
182           this.ajvService.addMetaSchema(metaSchema);\r
183           this.ajvService._opts.defaultMeta = metaSchema.id;\r
184 \r
185           // Optionally you can also disable keywords defined in draft-06\r
186           this.ajvService.removeKeyword('propertyNames');\r
187           this.ajvService.removeKeyword('contains');\r
188           this.ajvService.removeKeyword('const');\r
189 \r
190         } else {\r
191           this.jsonMsg = 'Invalid JSON Schema Data Format -  jsonschema$schema version must be 04';\r
192           this.jsonErrMsgs = [];\r
193           return;\r
194         }\r
195       } catch (ajvErrMsg) {\r
196 \r
197         this.jsonMsg = 'Failed - Schema checking initialization: ' + ajvErrMsg;\r
198         this.jsonErrMsgs = [];\r
199         return;\r
200       }\r
201 \r
202 \r
203       try {\r
204         const pschema = JSON.parse(this.dfschema);\r
205         const jsonSchema = pschema.jsonschema;\r
206 \r
207         const sValidate = this.ajvService.compile(jsonSchema);\r
208         const result = sValidate(JSON.parse(this.dfjson));\r
209 \r
210         let j = 0;\r
211         if (result === false) {\r
212           for ( const errMsg of Object.keys(sValidate.errors)) {\r
213              let msg = sValidate.errors[errMsg].message;\r
214              if (sValidate.errors[errMsg].hasOwnProperty('params')) {\r
215                if (sValidate.errors[errMsg].params.hasOwnProperty('additionalProperty')) {\r
216                  msg = msg + ' - ';\r
217                  msg = msg + sValidate.errors[errMsg].params.additionalProperty;\r
218                }\r
219              }\r
220              let dupMsg = false;\r
221              for (const k in this.jsonErrMsgs) {\r
222                if ( this.jsonErrMsgs[k] === msg) {\r
223                  dupMsg = true;\r
224                }\r
225              }\r
226              if (dupMsg ===  false) {\r
227               this.jsonErrMsgs[j] = msg;\r
228               j = j + 1;\r
229              }\r
230           }\r
231           this.jsonMsg = 'JSON Input does not match Schema:';\r
232           return;\r
233         }\r
234       } catch (schemaError) {\r
235         this.jsonMsg = 'Unexpected Schema Validation Error' + schemaError;\r
236         return;\r
237       }\r
238       this.jsonMsg = 'JSON Input Validated';\r
239       this.jsonErrMsgs = [];\r
240   }\r
241 \r
242   doDFJSONChange(ev: any) {\r
243       this.dfjson = ev.target.value;\r
244       this.validateJSON();\r
245   }\r
246 }\r