@kravc/schema 2.3.1 → 2.3.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kravc/schema",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
4
4
  "description": "Advanced JSON schema manipulation and validation library.",
5
5
  "keywords": [
6
6
  "JSON",
@@ -35,7 +35,7 @@
35
35
  "lodash.uniq": "^4.5.0",
36
36
  "security-context": "^4.0.0",
37
37
  "validator": "^13.7.0",
38
- "z-schema": "^5.0.2"
38
+ "z-schema": "^5.0.5"
39
39
  },
40
40
  "devDependencies": {
41
41
  "chai": "^4.3.4",
package/src/Validator.js CHANGED
@@ -46,9 +46,29 @@ class Validator {
46
46
  throw new Error(`Schema "${schemaId}" not found`)
47
47
  }
48
48
 
49
- const result = JSON.parse(JSON.stringify(object))
50
- cleanupAttributes(result, jsonSchema, this._jsonSchemasMap)
51
- normalizeAttributes(result, jsonSchema, this._jsonSchemasMap)
49
+ const objectJson = JSON.stringify(object)
50
+ const result = JSON.parse(objectJson)
51
+
52
+ try {
53
+ // NOTE: Drop attributes from objects that are not defined in schema.
54
+ // This is bad for FE developers, as they continue to send some
55
+ // trash to endpoints, but good for integrations with third party
56
+ // services, e.g. Telegram, when you do not want to define schema
57
+ // for the full payload. This method currently fails for cases when
58
+ // attribute is defined as object or array in schema, but value is
59
+ // a string. In this case validation method below would catch that.
60
+ cleanupAttributes(result, jsonSchema, this._jsonSchemasMap)
61
+
62
+ // NOTE: Normalize method helps to integrate objects built from URLs,
63
+ // where types are not defined, e.g. booleans are '1', 'yes' string
64
+ // or numbers are '1', '2'... strings.
65
+ normalizeAttributes(result, jsonSchema, this._jsonSchemasMap)
66
+
67
+ } catch (error) {
68
+ // NOTE: Skip errors in cleanup and normalize attributes methods,
69
+ // validation fails for objects with invalid value types.
70
+
71
+ }
52
72
 
53
73
  const isValid = this._engine.validate(result, jsonSchema)
54
74
 
@@ -137,12 +137,50 @@ describe('Validator', () => {
137
137
  expect(validInput.preferences.isNotificationEnabled).to.eql(false)
138
138
 
139
139
  expect(() => {
140
+ input.preferences.isNotificationEnabled = 'NaN'
141
+ validInput = validator.validate(input, 'Profile')
142
+ expect(validInput.preferences.isNotificationEnabled).to.eql('NaN')
143
+ }).to.throw('"Profile" validation failed')
144
+
145
+ expect(() => {
146
+ input.preferences.isNotificationEnabled = 0
140
147
  input.preferences.height = 'NaN'
141
148
  validInput = validator.validate(input, 'Profile')
142
149
  expect(validInput.preferences.height).to.eql('NaN')
143
150
  }).to.throw('"Profile" validation failed')
144
151
  })
145
152
 
153
+ it('throws validation error if cleanup or normalize method failed', () => {
154
+ const validator = new Validator(SCHEMAS)
155
+
156
+ const input = {
157
+ name: 'Oleksandr',
158
+ contactDetails: {
159
+ email: 'a@kra.vc'
160
+ },
161
+ favoriteItems: 'NOT_ARRAY_BUT_STRING'
162
+ }
163
+
164
+ try {
165
+ validator.validate(input, 'Profile')
166
+
167
+ } catch (validationError) {
168
+ const error = validationError.toJSON()
169
+
170
+ expect(error.object).to.exist
171
+ expect(error.code).to.eql('ValidationError')
172
+ expect(error.message).to.eql('"Profile" validation failed')
173
+ expect(error.schemaId).to.eql('Profile')
174
+
175
+ const errorMessage = error.validationErrors[0].message
176
+ expect(errorMessage).to.eql('Expected type array but found type string')
177
+
178
+ return
179
+ }
180
+
181
+ throw new Error('Validation error is not thrown')
182
+ })
183
+
146
184
  it('throws error if validation failed', () => {
147
185
  const validator = new Validator(SCHEMAS)
148
186
 
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ const BOOLEAN_STRING_TRUE_VALUES = ['yes', 'true', '1']
4
+ const BOOLEAN_STRING_FALSE_VALUES = ['no', 'false', '0']
5
+
3
6
  const normalizeType = (type, value) => {
4
7
  let normalizedValue = value
5
8
 
@@ -22,8 +25,12 @@ const normalizeType = (type, value) => {
22
25
  }
23
26
 
24
27
  if (isStringValue) {
25
- const isTrue = value.toLowerCase() === 'true' || value === '1'
26
- normalizedValue = isTrue ? true : false
28
+ const isTrue = BOOLEAN_STRING_TRUE_VALUES.includes(value.toLowerCase())
29
+ const isFalse = BOOLEAN_STRING_FALSE_VALUES.includes(value.toLowerCase())
30
+
31
+ if (isTrue || isFalse) {
32
+ normalizedValue = isTrue ? true : false
33
+ }
27
34
  }
28
35
  }
29
36
  }