@kravc/schema 2.7.6 → 2.8.0-alpha.1
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/README.md +19 -14
- package/dist/CredentialFactory.d.ts +345 -0
- package/dist/CredentialFactory.d.ts.map +1 -0
- package/dist/CredentialFactory.js +381 -0
- package/dist/CredentialFactory.js.map +1 -0
- package/dist/Schema.d.ts +448 -0
- package/dist/Schema.d.ts.map +1 -0
- package/dist/Schema.js +506 -0
- package/dist/Schema.js.map +1 -0
- package/dist/ValidationError.d.ts +70 -0
- package/dist/ValidationError.d.ts.map +1 -0
- package/dist/ValidationError.js +78 -0
- package/dist/ValidationError.js.map +1 -0
- package/dist/Validator.d.ts +483 -0
- package/dist/Validator.d.ts.map +1 -0
- package/dist/Validator.js +570 -0
- package/dist/Validator.js.map +1 -0
- package/dist/helpers/JsonSchema.d.ts +99 -0
- package/dist/helpers/JsonSchema.d.ts.map +1 -0
- package/dist/helpers/JsonSchema.js +3 -0
- package/dist/helpers/JsonSchema.js.map +1 -0
- package/dist/helpers/cleanupAttributes.d.ts +34 -0
- package/dist/helpers/cleanupAttributes.d.ts.map +1 -0
- package/dist/helpers/cleanupAttributes.js +113 -0
- package/dist/helpers/cleanupAttributes.js.map +1 -0
- package/dist/helpers/cleanupNulls.d.ts +27 -0
- package/dist/helpers/cleanupNulls.d.ts.map +1 -0
- package/dist/helpers/cleanupNulls.js +96 -0
- package/dist/helpers/cleanupNulls.js.map +1 -0
- package/dist/helpers/createSchemasMap.d.ts +67 -0
- package/dist/helpers/createSchemasMap.d.ts.map +1 -0
- package/dist/helpers/createSchemasMap.js +200 -0
- package/dist/helpers/createSchemasMap.js.map +1 -0
- package/dist/helpers/getReferenceIds.d.ts +169 -0
- package/dist/helpers/getReferenceIds.d.ts.map +1 -0
- package/dist/helpers/getReferenceIds.js +241 -0
- package/dist/helpers/getReferenceIds.js.map +1 -0
- package/dist/helpers/got.d.ts +60 -0
- package/dist/helpers/got.d.ts.map +1 -0
- package/dist/helpers/got.js +72 -0
- package/dist/helpers/got.js.map +1 -0
- package/dist/helpers/mapObjectProperties.d.ts +150 -0
- package/dist/helpers/mapObjectProperties.d.ts.map +1 -0
- package/dist/helpers/mapObjectProperties.js +229 -0
- package/dist/helpers/mapObjectProperties.js.map +1 -0
- package/dist/helpers/normalizeAttributes.d.ts +213 -0
- package/dist/helpers/normalizeAttributes.d.ts.map +1 -0
- package/dist/helpers/normalizeAttributes.js +243 -0
- package/dist/helpers/normalizeAttributes.js.map +1 -0
- package/dist/helpers/normalizeProperties.d.ts +168 -0
- package/dist/helpers/normalizeProperties.d.ts.map +1 -0
- package/dist/helpers/normalizeProperties.js +223 -0
- package/dist/helpers/normalizeProperties.js.map +1 -0
- package/dist/helpers/normalizeRequired.d.ts +159 -0
- package/dist/helpers/normalizeRequired.d.ts.map +1 -0
- package/dist/helpers/normalizeRequired.js +206 -0
- package/dist/helpers/normalizeRequired.js.map +1 -0
- package/dist/helpers/normalizeType.d.ts +81 -0
- package/dist/helpers/normalizeType.d.ts.map +1 -0
- package/dist/helpers/normalizeType.js +210 -0
- package/dist/helpers/normalizeType.js.map +1 -0
- package/dist/helpers/nullifyEmptyValues.d.ts +139 -0
- package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -0
- package/dist/helpers/nullifyEmptyValues.js +191 -0
- package/dist/helpers/nullifyEmptyValues.js.map +1 -0
- package/dist/helpers/removeRequiredAndDefault.d.ts +106 -0
- package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -0
- package/dist/helpers/removeRequiredAndDefault.js +138 -0
- package/dist/helpers/removeRequiredAndDefault.js.map +1 -0
- package/dist/helpers/validateId.d.ts +39 -0
- package/dist/helpers/validateId.d.ts.map +1 -0
- package/dist/helpers/validateId.js +51 -0
- package/dist/helpers/validateId.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/ld/documentLoader.d.ts +8 -0
- package/dist/ld/documentLoader.d.ts.map +1 -0
- package/dist/ld/documentLoader.js +24 -0
- package/dist/ld/documentLoader.js.map +1 -0
- package/dist/ld/getLinkedDataAttributeType.d.ts +10 -0
- package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -0
- package/dist/ld/getLinkedDataAttributeType.js +32 -0
- package/dist/ld/getLinkedDataAttributeType.js.map +1 -0
- package/dist/ld/getLinkedDataContext.d.ts +19 -0
- package/dist/ld/getLinkedDataContext.d.ts.map +1 -0
- package/dist/ld/getLinkedDataContext.js +50 -0
- package/dist/ld/getLinkedDataContext.js.map +1 -0
- package/eslint.config.mjs +32 -52
- package/examples/credentials/createAccountCredential.ts +27 -0
- package/examples/credentials/createMineSweeperScoreCredential.ts +115 -0
- package/examples/index.ts +7 -0
- package/examples/schemas/FavoriteItemSchema.ts +27 -0
- package/examples/{Preferences.yaml → schemas/Preferences.yaml} +2 -0
- package/examples/schemas/PreferencesSchema.ts +29 -0
- package/examples/schemas/ProfileSchema.ts +91 -0
- package/examples/schemas/Status.yaml +3 -0
- package/examples/schemas/StatusSchema.ts +12 -0
- package/jest.config.mjs +5 -0
- package/package.json +27 -20
- package/src/CredentialFactory.ts +392 -0
- package/src/Schema.ts +583 -0
- package/src/ValidationError.ts +90 -0
- package/src/Validator.ts +603 -0
- package/src/__tests__/CredentialFactory.test.ts +588 -0
- package/src/__tests__/Schema.test.ts +371 -0
- package/src/__tests__/ValidationError.test.ts +235 -0
- package/src/__tests__/Validator.test.ts +787 -0
- package/src/helpers/JsonSchema.ts +119 -0
- package/src/helpers/__tests__/cleanupAttributes.test.ts +943 -0
- package/src/helpers/__tests__/cleanupNulls.test.ts +772 -0
- package/src/helpers/__tests__/createSchemasMap.test.ts +238 -0
- package/src/helpers/__tests__/getReferenceIds.test.ts +975 -0
- package/src/helpers/__tests__/got.test.ts +193 -0
- package/src/helpers/__tests__/mapObjectProperties.test.ts +1126 -0
- package/src/helpers/__tests__/normalizeAttributes.test.ts +1435 -0
- package/src/helpers/__tests__/normalizeProperties.test.ts +727 -0
- package/src/helpers/__tests__/normalizeRequired.test.ts +669 -0
- package/src/helpers/__tests__/normalizeType.test.ts +772 -0
- package/src/helpers/__tests__/nullifyEmptyValues.test.ts +735 -0
- package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +734 -0
- package/src/helpers/__tests__/validateId.test.ts +118 -0
- package/src/helpers/cleanupAttributes.ts +151 -0
- package/src/helpers/cleanupNulls.ts +106 -0
- package/src/helpers/createSchemasMap.ts +212 -0
- package/src/helpers/getReferenceIds.ts +273 -0
- package/src/helpers/got.ts +73 -0
- package/src/helpers/mapObjectProperties.ts +272 -0
- package/src/helpers/normalizeAttributes.ts +247 -0
- package/src/helpers/normalizeProperties.ts +249 -0
- package/src/helpers/normalizeRequired.ts +233 -0
- package/src/helpers/normalizeType.ts +235 -0
- package/src/helpers/nullifyEmptyValues.ts +207 -0
- package/src/helpers/removeRequiredAndDefault.ts +151 -0
- package/src/helpers/validateId.ts +53 -0
- package/src/index.ts +17 -0
- package/src/ld/__tests__/documentLoader.test.ts +57 -0
- package/src/ld/__tests__/getLinkedDataAttributeType.test.ts +212 -0
- package/src/ld/__tests__/getLinkedDataContext.test.ts +378 -0
- package/src/ld/documentLoader.ts +28 -0
- package/src/ld/getLinkedDataAttributeType.ts +46 -0
- package/src/ld/getLinkedDataContext.ts +80 -0
- package/tsconfig.json +27 -0
- package/types/credentials-context.d.ts +14 -0
- package/types/security-context.d.ts +6 -0
- package/examples/Status.yaml +0 -3
- package/examples/createAccountCredential.js +0 -27
- package/examples/createMineSweeperScoreCredential.js +0 -63
- package/examples/index.js +0 -9
- package/src/CredentialFactory.js +0 -67
- package/src/CredentialFactory.spec.js +0 -131
- package/src/Schema.js +0 -104
- package/src/Schema.spec.js +0 -172
- package/src/ValidationError.js +0 -31
- package/src/Validator.js +0 -128
- package/src/Validator.spec.js +0 -355
- package/src/helpers/cleanupAttributes.js +0 -71
- package/src/helpers/cleanupNulls.js +0 -42
- package/src/helpers/getReferenceIds.js +0 -71
- package/src/helpers/mapObject.js +0 -65
- package/src/helpers/normalizeAttributes.js +0 -28
- package/src/helpers/normalizeProperties.js +0 -61
- package/src/helpers/normalizeRequired.js +0 -37
- package/src/helpers/normalizeType.js +0 -41
- package/src/helpers/nullifyEmptyValues.js +0 -57
- package/src/helpers/removeRequiredAndDefault.js +0 -30
- package/src/helpers/validateId.js +0 -19
- package/src/index.d.ts +0 -25
- package/src/index.js +0 -8
- package/src/ld/documentLoader.js +0 -25
- package/src/ld/documentLoader.spec.js +0 -12
- package/src/ld/getLinkedDataContext.js +0 -63
- package/src/ld/getLinkedDataType.js +0 -38
- /package/examples/{FavoriteItem.yaml → schemas/FavoriteItem.yaml} +0 -0
- /package/examples/{Profile.yaml → schemas/Profile.yaml} +0 -0
package/src/Validator.spec.js
DELETED
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { load } = require('js-yaml')
|
|
4
|
-
const { expect } = require('chai')
|
|
5
|
-
const { readFileSync } = require('fs')
|
|
6
|
-
const { Schema, Validator } = require('src')
|
|
7
|
-
|
|
8
|
-
const loadSync = (yamlPath) => {
|
|
9
|
-
const id = yamlPath.split('.')[0].split('/').reverse()[0]
|
|
10
|
-
const source = load(readFileSync(yamlPath))
|
|
11
|
-
|
|
12
|
-
return new Schema(source, id)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const SCHEMAS = [
|
|
16
|
-
'examples/Status.yaml',
|
|
17
|
-
'examples/Profile.yaml',
|
|
18
|
-
'examples/Preferences.yaml',
|
|
19
|
-
'examples/FavoriteItem.yaml'
|
|
20
|
-
].map(path => loadSync(path))
|
|
21
|
-
|
|
22
|
-
describe('Validator', () => {
|
|
23
|
-
describe('Validator.constructor(schemas)', () => {
|
|
24
|
-
it('create validator for schemas', () => {
|
|
25
|
-
new Validator(SCHEMAS)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('throws error if no schemas provided', () => {
|
|
29
|
-
expect(
|
|
30
|
-
() => new Validator()
|
|
31
|
-
).to.throw('No schemas provided')
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('throws error if referenced schema not found', () => {
|
|
35
|
-
const entitySchema = new Schema({ name: { $ref: 'MissingSchema' } }, 'Entity')
|
|
36
|
-
|
|
37
|
-
expect(
|
|
38
|
-
() => new Validator([ ...SCHEMAS, entitySchema ])
|
|
39
|
-
).to.throw('Schemas validation failed:')
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
describe('.validate(object, schemaId, shouldNullifyEmptyValues = false, shouldCleanupNulls = true)', () => {
|
|
44
|
-
it('returns validated, cleaned and normalized object', () => {
|
|
45
|
-
const validator = new Validator(SCHEMAS)
|
|
46
|
-
|
|
47
|
-
const _createdAt = new Date().toISOString()
|
|
48
|
-
|
|
49
|
-
const input = {
|
|
50
|
-
name: 'Oleksandr',
|
|
51
|
-
toBeRemoved: null,
|
|
52
|
-
contactDetails: {
|
|
53
|
-
email: 'a@kra.vc',
|
|
54
|
-
toBeRemoved: null,
|
|
55
|
-
},
|
|
56
|
-
favoriteItems: [
|
|
57
|
-
{
|
|
58
|
-
id: '1',
|
|
59
|
-
name: 'Student Book',
|
|
60
|
-
categories: [ 'Education' ],
|
|
61
|
-
toBeRemoved: null,
|
|
62
|
-
_createdAt
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
locations: [{
|
|
66
|
-
name: 'Home',
|
|
67
|
-
address: {
|
|
68
|
-
type: 'Primary',
|
|
69
|
-
zip: '03119',
|
|
70
|
-
city: 'Kyiv',
|
|
71
|
-
addressLine1: 'Melnikova 83-D, 78',
|
|
72
|
-
_createdAt
|
|
73
|
-
},
|
|
74
|
-
_createdAt
|
|
75
|
-
}],
|
|
76
|
-
preferences: {
|
|
77
|
-
height: 180,
|
|
78
|
-
isNotificationEnabled: true,
|
|
79
|
-
_createdAt
|
|
80
|
-
},
|
|
81
|
-
status: 'Active',
|
|
82
|
-
_createdAt
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const validInput = validator.validate(input, 'Profile', false, true)
|
|
86
|
-
|
|
87
|
-
expect(validInput.toBeRemoved).to.not.exist
|
|
88
|
-
expect(validInput.contactDetails.toBeRemoved).to.not.exist
|
|
89
|
-
expect(validInput.favoriteItems[0].toBeRemoved).to.not.exist
|
|
90
|
-
|
|
91
|
-
expect(validInput._createdAt).to.not.exist
|
|
92
|
-
expect(validInput.preferences._createdAt).to.not.exist
|
|
93
|
-
expect(validInput.locations[0]._createdAt).to.not.exist
|
|
94
|
-
expect(validInput.locations[0].address._createdAt).to.not.exist
|
|
95
|
-
expect(validInput.favoriteItems[0]._createdAt).to.not.exist
|
|
96
|
-
|
|
97
|
-
expect(validInput.name).to.eql('Oleksandr')
|
|
98
|
-
expect(validInput.gender).to.eql('Other')
|
|
99
|
-
expect(validInput.status).to.eql('Active')
|
|
100
|
-
expect(validInput.locations[0].name).to.eql('Home')
|
|
101
|
-
expect(validInput.locations[0].address.country).to.eql('Ukraine')
|
|
102
|
-
expect(validInput.locations[0].address.zip).to.eql('03119')
|
|
103
|
-
expect(validInput.locations[0].address.city).to.eql('Kyiv')
|
|
104
|
-
expect(validInput.locations[0].address.addressLine1).to.eql('Melnikova 83-D, 78',)
|
|
105
|
-
expect(validInput.locations[0].address.type).to.eql('Primary')
|
|
106
|
-
expect(validInput.favoriteItems[0].id).to.eql('1')
|
|
107
|
-
expect(validInput.favoriteItems[0].name).to.eql('Student Book')
|
|
108
|
-
expect(validInput.favoriteItems[0].categories).to.deep.eql([ 'Education' ])
|
|
109
|
-
expect(validInput.favoriteItems[0].status).to.eql('Pending')
|
|
110
|
-
expect(validInput.contactDetails.email).to.eql('a@kra.vc')
|
|
111
|
-
expect(validInput.contactDetails.mobileNumber).to.eql('380504112171')
|
|
112
|
-
expect(validInput.preferences.height).to.eql(180)
|
|
113
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql(true)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('normalizes object attributes according to property type', () => {
|
|
117
|
-
const validator = new Validator(SCHEMAS)
|
|
118
|
-
|
|
119
|
-
const input = {
|
|
120
|
-
name: 'Oleksandr',
|
|
121
|
-
contactDetails: {
|
|
122
|
-
email: 'a@kra.vc'
|
|
123
|
-
},
|
|
124
|
-
preferences: {
|
|
125
|
-
height: '180',
|
|
126
|
-
isNotificationEnabled: 'true'
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
let validInput
|
|
131
|
-
|
|
132
|
-
validInput = validator.validate(input, 'Profile')
|
|
133
|
-
expect(validInput.preferences.height).to.eql(180)
|
|
134
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql(true)
|
|
135
|
-
|
|
136
|
-
input.preferences.isNotificationEnabled = '1'
|
|
137
|
-
validInput = validator.validate(input, 'Profile')
|
|
138
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql(true)
|
|
139
|
-
|
|
140
|
-
input.preferences.isNotificationEnabled = '0'
|
|
141
|
-
validInput = validator.validate(input, 'Profile')
|
|
142
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql(false)
|
|
143
|
-
|
|
144
|
-
input.preferences.isNotificationEnabled = 0
|
|
145
|
-
validInput = validator.validate(input, 'Profile')
|
|
146
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql(false)
|
|
147
|
-
|
|
148
|
-
expect(() => {
|
|
149
|
-
input.preferences.isNotificationEnabled = 'NaN'
|
|
150
|
-
validInput = validator.validate(input, 'Profile')
|
|
151
|
-
expect(validInput.preferences.isNotificationEnabled).to.eql('NaN')
|
|
152
|
-
}).to.throw('"Profile" validation failed')
|
|
153
|
-
|
|
154
|
-
expect(() => {
|
|
155
|
-
input.preferences.isNotificationEnabled = 0
|
|
156
|
-
input.preferences.height = 'NaN'
|
|
157
|
-
validInput = validator.validate(input, 'Profile')
|
|
158
|
-
expect(validInput.preferences.height).to.eql('NaN')
|
|
159
|
-
}).to.throw('"Profile" validation failed')
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('throws validation error if cleanup or normalize method failed', () => {
|
|
163
|
-
const validator = new Validator(SCHEMAS)
|
|
164
|
-
|
|
165
|
-
const input = {
|
|
166
|
-
name: 'Oleksandr',
|
|
167
|
-
contactDetails: {
|
|
168
|
-
email: 'a@kra.vc'
|
|
169
|
-
},
|
|
170
|
-
favoriteItems: 'NOT_ARRAY_BUT_STRING'
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
validator.validate(input, 'Profile')
|
|
175
|
-
|
|
176
|
-
} catch (validationError) {
|
|
177
|
-
const error = validationError.toJSON()
|
|
178
|
-
|
|
179
|
-
expect(error.object).to.exist
|
|
180
|
-
expect(error.code).to.eql('ValidationError')
|
|
181
|
-
expect(error.message).to.eql('"Profile" validation failed')
|
|
182
|
-
expect(error.schemaId).to.eql('Profile')
|
|
183
|
-
|
|
184
|
-
const errorMessage = error.validationErrors[0].message
|
|
185
|
-
expect(errorMessage).to.eql('Expected type array but found type string')
|
|
186
|
-
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
throw new Error('Validation error is not thrown')
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('throws error if validation failed', () => {
|
|
194
|
-
const validator = new Validator(SCHEMAS)
|
|
195
|
-
|
|
196
|
-
const input = {}
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
validator.validate(input, 'Profile')
|
|
200
|
-
|
|
201
|
-
} catch (validationError) {
|
|
202
|
-
const error = validationError.toJSON()
|
|
203
|
-
|
|
204
|
-
expect(error.object).to.exist
|
|
205
|
-
expect(error.code).to.eql('ValidationError')
|
|
206
|
-
expect(error.message).to.eql('"Profile" validation failed')
|
|
207
|
-
expect(error.schemaId).to.eql('Profile')
|
|
208
|
-
|
|
209
|
-
expect(error.validationErrors).to.have.lengthOf(2)
|
|
210
|
-
|
|
211
|
-
return
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
throw new Error('Validation error is not thrown')
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
it('throws error if schema not found', () => {
|
|
218
|
-
const validator = new Validator(SCHEMAS)
|
|
219
|
-
|
|
220
|
-
expect(
|
|
221
|
-
() => validator.validate({}, 'Account')
|
|
222
|
-
).to.throw('Schema "Account" not found')
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
it('throws error if multiple schemas with same id', async () => {
|
|
226
|
-
const exampleSchema1 = new Schema({
|
|
227
|
-
number: { required: true }
|
|
228
|
-
}, 'Example')
|
|
229
|
-
|
|
230
|
-
const exampleSchema2 = new Schema({
|
|
231
|
-
id: {}
|
|
232
|
-
}, 'Example')
|
|
233
|
-
|
|
234
|
-
expect(() => new Validator([ exampleSchema1, exampleSchema2 ]))
|
|
235
|
-
.to.throw('Multiple "Example" schemas provided')
|
|
236
|
-
})
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
describe('.validate(object, schemaId, shouldNullifyEmptyValues = false)', () => {
|
|
240
|
-
it('throws validation error for attributes not matching format or pattern', () => {
|
|
241
|
-
const validator = new Validator(SCHEMAS)
|
|
242
|
-
|
|
243
|
-
const input = {
|
|
244
|
-
name: 'Oleksandr',
|
|
245
|
-
gender: '',
|
|
246
|
-
contactDetails: {
|
|
247
|
-
email: 'a@kra.vc',
|
|
248
|
-
secondaryEmail: '',
|
|
249
|
-
mobileNumber: '',
|
|
250
|
-
},
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
expect(
|
|
254
|
-
() => validator.validate(input, 'Profile')
|
|
255
|
-
).to.throw('"Profile" validation failed')
|
|
256
|
-
})
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
describe('.validate(object, schemaId, shouldNullifyEmptyValues = true)', () => {
|
|
260
|
-
it('returns input with cleaned up null values for not required attributes', () => {
|
|
261
|
-
const validator = new Validator(SCHEMAS)
|
|
262
|
-
|
|
263
|
-
const input = {
|
|
264
|
-
name: 'Oleksandr',
|
|
265
|
-
gender: '', // ENUM
|
|
266
|
-
contactDetails: {
|
|
267
|
-
email: 'a@kra.vc',
|
|
268
|
-
mobileNumber: '', // PATTERN
|
|
269
|
-
secondaryEmail: '', // FORMAT
|
|
270
|
-
},
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const validInput = validator.validate(input, 'Profile', true)
|
|
274
|
-
|
|
275
|
-
expect(validInput.gender).to.eql(null)
|
|
276
|
-
expect(validInput.contactDetails.mobileNumber).to.eql(null)
|
|
277
|
-
expect(validInput.contactDetails.secondaryEmail).to.eql(null)
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
it('throws validation errors for other attributes', () => {
|
|
281
|
-
const validator = new Validator(SCHEMAS)
|
|
282
|
-
|
|
283
|
-
const input = {
|
|
284
|
-
name: '', // code: MIN_LENGTH
|
|
285
|
-
gender: 'NONE', // code: ENUM_MISMATCH
|
|
286
|
-
contactDetails: {
|
|
287
|
-
email: 'a@kra.vc',
|
|
288
|
-
mobileNumber: 'abc', // code: PATTERN
|
|
289
|
-
secondaryEmail: '',
|
|
290
|
-
},
|
|
291
|
-
preferences: {
|
|
292
|
-
age: 'a' // code: INVALID_TYPE
|
|
293
|
-
},
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
validator.validate(input, 'Profile', true)
|
|
298
|
-
|
|
299
|
-
} catch (validationError) {
|
|
300
|
-
const error = validationError.toJSON()
|
|
301
|
-
|
|
302
|
-
expect(error.message).to.eql('"Profile" validation failed')
|
|
303
|
-
|
|
304
|
-
expect(error.validationErrors).to.have.lengthOf(4)
|
|
305
|
-
|
|
306
|
-
expect(error.validationErrors[0].code).to.eql('INVALID_TYPE')
|
|
307
|
-
expect(error.validationErrors[1].code).to.eql('PATTERN')
|
|
308
|
-
expect(error.validationErrors[2].code).to.eql('ENUM_MISMATCH')
|
|
309
|
-
expect(error.validationErrors[3].code).to.eql('MIN_LENGTH')
|
|
310
|
-
|
|
311
|
-
return
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
throw new Error('Validation error is not thrown')
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
describe('.normalize(object, schemaId)', () => {
|
|
319
|
-
it('returns normalized object clone', () => {
|
|
320
|
-
const validator = new Validator(SCHEMAS)
|
|
321
|
-
|
|
322
|
-
const input = {}
|
|
323
|
-
|
|
324
|
-
const normalizedInput = validator.normalize(input, 'Profile')
|
|
325
|
-
|
|
326
|
-
expect(normalizedInput.gender).to.eql('Other')
|
|
327
|
-
expect(normalizedInput.status).to.eql('Pending')
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
it('throws error if schema not found', () => {
|
|
331
|
-
const validator = new Validator(SCHEMAS)
|
|
332
|
-
|
|
333
|
-
expect(
|
|
334
|
-
() => validator.normalize({}, 'Account')
|
|
335
|
-
).to.throw('Schema "Account" not found')
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
describe('.schemasMap', () => {
|
|
340
|
-
it('returns schemas map', () => {
|
|
341
|
-
const validator = new Validator(SCHEMAS)
|
|
342
|
-
|
|
343
|
-
expect(validator.schemasMap).to.exist
|
|
344
|
-
})
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
describe('.getReferenceIds(schemaId)', () => {
|
|
348
|
-
it('returns ids of referenced schemas', () => {
|
|
349
|
-
const validator = new Validator(SCHEMAS)
|
|
350
|
-
const referenceIds = validator.getReferenceIds('Profile')
|
|
351
|
-
|
|
352
|
-
expect(referenceIds).to.eql([ 'Status', 'FavoriteItem', 'Preferences' ])
|
|
353
|
-
})
|
|
354
|
-
})
|
|
355
|
-
})
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isUndefined } = require('lodash')
|
|
4
|
-
|
|
5
|
-
const cleanupAttributes = (object, jsonSchema, schemasMap) => {
|
|
6
|
-
const { id, enum: isEnum } = jsonSchema
|
|
7
|
-
|
|
8
|
-
if (isEnum) { return }
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
for (const fieldName in object) {
|
|
12
|
-
const property = jsonSchema.properties[fieldName]
|
|
13
|
-
const isPropertyUndefined = isUndefined(property)
|
|
14
|
-
|
|
15
|
-
if (isPropertyUndefined) {
|
|
16
|
-
delete object[fieldName]
|
|
17
|
-
|
|
18
|
-
} else {
|
|
19
|
-
const { $ref: refSchemaId, properties, type } = property
|
|
20
|
-
|
|
21
|
-
const isArray = type === 'array'
|
|
22
|
-
const isObject = type === 'object'
|
|
23
|
-
const isReference = !isUndefined(refSchemaId)
|
|
24
|
-
|
|
25
|
-
if (isReference) {
|
|
26
|
-
const refJsonSchema = schemasMap[refSchemaId]
|
|
27
|
-
|
|
28
|
-
cleanupAttributes(object[fieldName], refJsonSchema, schemasMap)
|
|
29
|
-
|
|
30
|
-
} else if (isObject) {
|
|
31
|
-
const nestedJsonSchema = {
|
|
32
|
-
id: `${id}.${fieldName}.properties`,
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
cleanupAttributes(object[fieldName], nestedJsonSchema, schemasMap)
|
|
38
|
-
|
|
39
|
-
} else if (isArray) {
|
|
40
|
-
const { items } = property
|
|
41
|
-
const { $ref: itemRefSchemaId, properties: itemProperties } = items
|
|
42
|
-
|
|
43
|
-
const array = object[fieldName]
|
|
44
|
-
const isItemObject = !!itemProperties
|
|
45
|
-
const isItemReference = !!itemRefSchemaId
|
|
46
|
-
|
|
47
|
-
let itemJsonSchema
|
|
48
|
-
|
|
49
|
-
if (isItemReference) {
|
|
50
|
-
itemJsonSchema = schemasMap[itemRefSchemaId]
|
|
51
|
-
|
|
52
|
-
} else if (isItemObject) {
|
|
53
|
-
itemJsonSchema = {
|
|
54
|
-
id: `${id}.${fieldName}.item`,
|
|
55
|
-
type: 'object',
|
|
56
|
-
properties: itemProperties
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (itemJsonSchema) {
|
|
62
|
-
for (const item of array) {
|
|
63
|
-
cleanupAttributes(item, itemJsonSchema, schemasMap)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
module.exports = cleanupAttributes
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isArray } = Array
|
|
4
|
-
const { isObject, cloneDeep } = require('lodash')
|
|
5
|
-
|
|
6
|
-
const cleanupNulls = object => {
|
|
7
|
-
if (!isObject(object)) {
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
for (const key in object) {
|
|
12
|
-
const value = object[key]
|
|
13
|
-
|
|
14
|
-
if (isArray(value)) {
|
|
15
|
-
for (const item of value) {
|
|
16
|
-
cleanupNulls(item)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
continue
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (isObject(value)) {
|
|
23
|
-
cleanupNulls(value)
|
|
24
|
-
|
|
25
|
-
continue
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const isNull = value === null
|
|
29
|
-
|
|
30
|
-
if (isNull) {
|
|
31
|
-
delete object[key]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = input => {
|
|
37
|
-
const object = cloneDeep(input)
|
|
38
|
-
|
|
39
|
-
cleanupNulls(object)
|
|
40
|
-
|
|
41
|
-
return object
|
|
42
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isUndefined, uniq } = require('lodash')
|
|
4
|
-
const Schema = require('../Schema')
|
|
5
|
-
|
|
6
|
-
const getReferenceIds = (schema, schemasMap) => {
|
|
7
|
-
const getSchema = id => schemasMap[id]
|
|
8
|
-
|
|
9
|
-
let referenceIds = []
|
|
10
|
-
|
|
11
|
-
const { jsonSchema } = schema
|
|
12
|
-
const { id, enum: isEnum } = jsonSchema
|
|
13
|
-
|
|
14
|
-
if (isEnum) { return [] }
|
|
15
|
-
|
|
16
|
-
for (const propertyName in jsonSchema.properties) {
|
|
17
|
-
const property = jsonSchema.properties[propertyName]
|
|
18
|
-
|
|
19
|
-
const { $ref: refSchemaId, properties, items } = property
|
|
20
|
-
|
|
21
|
-
const isArray = property.type === 'array'
|
|
22
|
-
const isObject = property.type === 'object'
|
|
23
|
-
const isReference = !isUndefined(refSchemaId)
|
|
24
|
-
|
|
25
|
-
if (isReference) {
|
|
26
|
-
const refJsonSchema = getSchema(refSchemaId, `${id}.${propertyName}.$ref`)
|
|
27
|
-
const nestedReferenceIds = getReferenceIds(refJsonSchema, schemasMap)
|
|
28
|
-
|
|
29
|
-
referenceIds = [ ...referenceIds, refSchemaId, ...nestedReferenceIds ]
|
|
30
|
-
continue
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (isObject) {
|
|
35
|
-
const nestedSchema = new Schema(properties, `${id}.${propertyName}.properties`)
|
|
36
|
-
const nestedReferenceIds = getReferenceIds(nestedSchema, schemasMap)
|
|
37
|
-
|
|
38
|
-
referenceIds = [ ...referenceIds, ...nestedReferenceIds ]
|
|
39
|
-
continue
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!isArray) {
|
|
43
|
-
continue
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const itemProperties = items.properties
|
|
47
|
-
const itemRefSchemaId = items.$ref
|
|
48
|
-
|
|
49
|
-
let itemJsonSchema
|
|
50
|
-
|
|
51
|
-
if (itemRefSchemaId) {
|
|
52
|
-
itemJsonSchema = getSchema(itemRefSchemaId, `${id}.${propertyName}.items.$ref`)
|
|
53
|
-
const nestedReferenceIds = getReferenceIds(itemJsonSchema, schemasMap)
|
|
54
|
-
|
|
55
|
-
referenceIds = [ ...referenceIds, itemRefSchemaId, ...nestedReferenceIds ]
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (itemProperties) {
|
|
60
|
-
const itemSchema = new Schema(itemProperties, `${id}.${propertyName}.items.properties`)
|
|
61
|
-
const itemReferenceIds = getReferenceIds(itemSchema, schemasMap)
|
|
62
|
-
|
|
63
|
-
referenceIds = [ ...referenceIds, ...itemReferenceIds ]
|
|
64
|
-
continue
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return uniq(referenceIds)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
module.exports = getReferenceIds
|
package/src/helpers/mapObject.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isUndefined } = require('lodash')
|
|
4
|
-
|
|
5
|
-
const mapObject = (object, jsonSchema, schemasMap, callback) => {
|
|
6
|
-
const { id, enum: isEnum } = jsonSchema
|
|
7
|
-
|
|
8
|
-
if (isEnum) { return }
|
|
9
|
-
|
|
10
|
-
for (const propertyName in jsonSchema.properties) {
|
|
11
|
-
const property = jsonSchema.properties[propertyName]
|
|
12
|
-
|
|
13
|
-
callback(propertyName, property, object)
|
|
14
|
-
|
|
15
|
-
const { $ref: refSchemaId, properties, items } = property
|
|
16
|
-
|
|
17
|
-
const value = object[propertyName]
|
|
18
|
-
const isArray = property.type === 'array'
|
|
19
|
-
const isObject = property.type === 'object'
|
|
20
|
-
const isReference = !isUndefined(refSchemaId)
|
|
21
|
-
const isValueDefined = !isUndefined(value)
|
|
22
|
-
|
|
23
|
-
if (isValueDefined) {
|
|
24
|
-
if (isReference) {
|
|
25
|
-
const refJsonSchema = schemasMap[refSchemaId]
|
|
26
|
-
|
|
27
|
-
mapObject(value, refJsonSchema, schemasMap, callback)
|
|
28
|
-
|
|
29
|
-
} else if (isObject) {
|
|
30
|
-
const nestedJsonSchema = {
|
|
31
|
-
id: `${id}.${propertyName}.properties`,
|
|
32
|
-
type: 'object',
|
|
33
|
-
properties
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
mapObject(value, nestedJsonSchema, schemasMap, callback)
|
|
37
|
-
|
|
38
|
-
} else if (isArray) {
|
|
39
|
-
const itemProperties = items.properties
|
|
40
|
-
const itemRefSchemaId = items.$ref
|
|
41
|
-
|
|
42
|
-
let itemJsonSchema
|
|
43
|
-
|
|
44
|
-
if (itemRefSchemaId) {
|
|
45
|
-
itemJsonSchema = schemasMap[itemRefSchemaId]
|
|
46
|
-
|
|
47
|
-
} else if (itemProperties) {
|
|
48
|
-
itemJsonSchema = {
|
|
49
|
-
id: `${id}.${propertyName}.items.properties`,
|
|
50
|
-
type: 'object',
|
|
51
|
-
properties: itemProperties
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (itemJsonSchema) {
|
|
56
|
-
for (const valueItem of value) {
|
|
57
|
-
mapObject(valueItem, itemJsonSchema, schemasMap, callback)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
module.exports = mapObject
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const mapObject = require('./mapObject')
|
|
4
|
-
const normalizeType = require('./normalizeType')
|
|
5
|
-
const { isUndefined } = require('lodash')
|
|
6
|
-
|
|
7
|
-
const normalizeAttributes = (object, jsonSchema, jsonSchemasMap) => {
|
|
8
|
-
const callback = (propertyName, propertySchema, object) => {
|
|
9
|
-
const value = object[propertyName]
|
|
10
|
-
|
|
11
|
-
const { type, default: defaultValue } = propertySchema
|
|
12
|
-
|
|
13
|
-
const hasDefaultValue = !isUndefined(defaultValue)
|
|
14
|
-
const isValueDefined = !isUndefined(value)
|
|
15
|
-
|
|
16
|
-
if (hasDefaultValue && !isValueDefined) {
|
|
17
|
-
object[propertyName] = defaultValue
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (type && isValueDefined) {
|
|
21
|
-
object[propertyName] = normalizeType(type, value)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
mapObject(object, jsonSchema, jsonSchemasMap, callback)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
module.exports = normalizeAttributes
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isUndefined } = require('lodash')
|
|
4
|
-
|
|
5
|
-
const normalizeProperties = properties => {
|
|
6
|
-
const { enum: isEnum } = properties
|
|
7
|
-
|
|
8
|
-
if (isEnum) {
|
|
9
|
-
properties.type = properties.type || 'string'
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
for (const name in properties) {
|
|
14
|
-
const property = properties[name]
|
|
15
|
-
|
|
16
|
-
const { type: hasType, $ref: isRef, items: hasItems, properties: hasProperties } = property
|
|
17
|
-
|
|
18
|
-
if (!isRef) {
|
|
19
|
-
if (!hasType) {
|
|
20
|
-
if (hasProperties) {
|
|
21
|
-
property.type = 'object'
|
|
22
|
-
|
|
23
|
-
} else if (hasItems) {
|
|
24
|
-
property.type = 'array'
|
|
25
|
-
|
|
26
|
-
} else {
|
|
27
|
-
property.type = 'string'
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const isArray = property.type === 'array'
|
|
33
|
-
const isObject = property.type === 'object'
|
|
34
|
-
|
|
35
|
-
if (isObject) {
|
|
36
|
-
if (!hasProperties) {
|
|
37
|
-
property.properties = {}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
normalizeProperties(property.properties)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (isArray) {
|
|
44
|
-
if (hasItems) {
|
|
45
|
-
const isItemObject = !isUndefined(property.items.properties)
|
|
46
|
-
|
|
47
|
-
if (isItemObject) {
|
|
48
|
-
property.items.type = 'object'
|
|
49
|
-
normalizeProperties(property.items.properties)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
} else {
|
|
53
|
-
property.items = { type: 'string' }
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
module.exports = normalizeProperties
|