schema-shield 0.0.2 → 0.0.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.
@@ -1,140 +1,118 @@
1
- import { CompiledSchema, ValidatorFunction } from "../index";
2
- import { ValidationError, isObject } from "../utils";
1
+ import { isCompiledSchema, isObject } from "../utils";
3
2
 
4
- export const ObjectKeywords: Record<string, ValidatorFunction> = {
3
+ import { KeywordFunction } from "../index";
4
+
5
+ export const ObjectKeywords: Record<string, KeywordFunction | false> = {
5
6
  // Object
6
- required(schema, data, pointer) {
7
+ required(schema, data, defineError) {
7
8
  if (!isObject(data)) {
8
- return {
9
- valid: true,
10
- errors: [],
11
- data
12
- };
9
+ return;
13
10
  }
14
11
 
15
- const errors = [];
16
12
  for (let i = 0; i < schema.required.length; i++) {
17
13
  const key = schema.required[i];
18
14
  if (!data.hasOwnProperty(key)) {
19
- errors.push(
20
- new ValidationError("Missing required property", {
21
- pointer: `${pointer}/${key}`,
22
- value: data,
23
- code: "MISSING_REQUIRED_PROPERTY"
24
- })
25
- );
15
+ return defineError("Required property is missing", {
16
+ item: key,
17
+ data: data[key]
18
+ });
26
19
  }
27
20
  }
28
21
 
29
- return { valid: errors.length === 0, errors, data };
22
+ return;
30
23
  },
31
24
 
32
- properties(schema, data, pointer, schemaShieldInstance) {
25
+ properties(schema, data, defineError) {
33
26
  if (!isObject(data)) {
34
- return { valid: true, errors: [], data };
35
- }
36
-
37
- const errors = [];
38
- let finalData = { ...data };
39
- for (let key in schema.properties) {
40
- if (!data.hasOwnProperty(key) || typeof data[key] === "undefined") {
41
- if (
42
- isObject(schema.properties[key]) &&
43
- "default" in schema.properties[key]
44
- ) {
45
- finalData[key] = schema.properties[key].default;
46
- }
27
+ return;
28
+ }
47
29
 
30
+ for (const key of Object.keys(schema.properties)) {
31
+ if (!data.hasOwnProperty(key)) {
32
+ const schemaProp = schema.properties[key];
33
+ if (isObject(schemaProp) && "default" in schemaProp) {
34
+ data[key] = schemaProp.default;
35
+ }
48
36
  continue;
49
37
  }
50
38
 
51
39
  if (typeof schema.properties[key] === "boolean") {
52
40
  if (schema.properties[key] === false) {
53
- errors.push(
54
- new ValidationError("Property is not allowed", {
55
- pointer: `${pointer}/${key}`,
56
- value: data[key],
57
- code: "PROPERTY_NOT_ALLOWED"
58
- })
59
- );
41
+ return defineError("Property is not allowed", {
42
+ item: key,
43
+ data: data[key]
44
+ });
60
45
  }
61
46
  continue;
62
47
  }
63
48
 
64
- const { validator } = schema.properties[key] as CompiledSchema;
65
- if (!validator) {
66
- continue;
49
+ if ("$validate" in schema.properties[key]) {
50
+ const error = schema.properties[key].$validate(data[key]);
51
+ if (error) {
52
+ return defineError("Property is invalid", {
53
+ item: key,
54
+ cause: error,
55
+ data: data[key]
56
+ });
57
+ }
67
58
  }
59
+ }
68
60
 
69
- const validatorResult = validator(
70
- schema.properties[key],
71
- finalData[key],
72
- `${pointer}/${key}`,
73
- schemaShieldInstance
74
- );
61
+ return;
62
+ },
75
63
 
76
- finalData[key] = validatorResult.data;
64
+ values(schema, data, defineError) {
65
+ if (!isObject(data) || !isCompiledSchema(schema.values)) {
66
+ return;
67
+ }
77
68
 
78
- if (!validatorResult.valid) {
79
- errors.push(...validatorResult.errors);
69
+ const keys = Object.keys(data);
70
+ for (const key of keys) {
71
+ const error = schema.values.$validate(data[key]);
72
+ if (error) {
73
+ return defineError("Property is invalid", {
74
+ item: key,
75
+ cause: error,
76
+ data: data[key]
77
+ });
80
78
  }
81
79
  }
82
80
 
83
- return { valid: errors.length === 0, errors, data: finalData };
81
+ return;
84
82
  },
85
83
 
86
- maxProperties(schema, data, pointer) {
84
+ maxProperties(schema, data, defineError) {
87
85
  if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
88
- return { valid: true, errors: [], data };
89
- }
90
-
91
- return {
92
- valid: false,
93
- errors: [
94
- new ValidationError("Object has too many properties", {
95
- pointer,
96
- value: data,
97
- code: "OBJECT_TOO_MANY_PROPERTIES"
98
- })
99
- ],
100
- data
101
- };
86
+ return;
87
+ }
88
+
89
+ return defineError("Too many properties", { data });
102
90
  },
103
91
 
104
- minProperties(schema, data, pointer) {
92
+ minProperties(schema, data, defineError) {
105
93
  if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
106
- return { valid: true, errors: [], data };
107
- }
108
-
109
- return {
110
- valid: false,
111
- errors: [
112
- new ValidationError("Object has too few properties", {
113
- pointer,
114
- value: data,
115
- code: "OBJECT_TOO_FEW_PROPERTIES"
116
- })
117
- ],
118
- data
119
- };
94
+ return;
95
+ }
96
+
97
+ return defineError("Too few properties", { data });
120
98
  },
121
99
 
122
- additionalProperties(schema, data, pointer, schemaShieldInstance) {
100
+ additionalProperties(schema, data, defineError) {
123
101
  if (!isObject(data)) {
124
- return { valid: true, errors: [], data };
102
+ return;
125
103
  }
126
104
 
127
- const errors = [];
128
- let finalData = { ...data };
129
- for (let key in data) {
105
+ const keys = Object.keys(data);
106
+ const isCompiled = isCompiledSchema(schema.additionalProperties);
107
+ for (const key of keys) {
130
108
  if (schema.properties && schema.properties.hasOwnProperty(key)) {
131
109
  continue;
132
110
  }
133
111
 
134
112
  if (schema.patternProperties) {
135
113
  let match = false;
136
- for (let pattern in schema.patternProperties) {
137
- if (new RegExp(pattern).test(key)) {
114
+ for (const pattern in schema.patternProperties) {
115
+ if (new RegExp(pattern, "u").test(key)) {
138
116
  match = true;
139
117
  break;
140
118
  }
@@ -145,86 +123,163 @@ export const ObjectKeywords: Record<string, ValidatorFunction> = {
145
123
  }
146
124
 
147
125
  if (schema.additionalProperties === false) {
148
- errors.push(
149
- new ValidationError("Additional property not allowed", {
150
- pointer: `${pointer}/${key}`,
151
- value: data,
152
- code: "ADDITIONAL_PROPERTY_NOT_ALLOWED"
153
- })
154
- );
155
- continue;
156
- }
157
-
158
- const { validator } = schema.additionalProperties as CompiledSchema;
159
- if (!validator) {
160
- continue;
126
+ return defineError("Additional properties are not allowed", {
127
+ item: key,
128
+ data: data[key]
129
+ });
161
130
  }
162
131
 
163
- const validatorResult = validator(
164
- schema.additionalProperties,
165
- finalData[key],
166
- `${pointer}/${key}`,
167
- schemaShieldInstance
168
- );
169
-
170
- finalData[key] = validatorResult.data;
171
-
172
- if (!validatorResult.valid) {
173
- errors.push(...validatorResult.errors);
132
+ if (isCompiled) {
133
+ const error = schema.additionalProperties.$validate(data[key]);
134
+ if (error) {
135
+ return defineError("Additional properties are invalid", {
136
+ item: key,
137
+ cause: error,
138
+ data: data[key]
139
+ });
140
+ }
174
141
  }
175
142
  }
176
143
 
177
- return { valid: errors.length === 0, errors, data: finalData };
144
+ return;
178
145
  },
179
146
 
180
- patternProperties(schema, data, pointer, schemaShieldInstance) {
147
+ patternProperties(schema, data, defineError) {
181
148
  if (!isObject(data)) {
182
- return { valid: true, errors: [], data };
149
+ return;
183
150
  }
184
151
 
185
- const errors = [];
186
- let finalData = { ...data };
187
- for (let pattern in schema.patternProperties) {
152
+ const patterns = Object.keys(schema.patternProperties);
153
+ for (const pattern of patterns) {
154
+ const regex = new RegExp(pattern, "u");
188
155
  if (typeof schema.patternProperties[pattern] === "boolean") {
189
156
  if (schema.patternProperties[pattern] === false) {
190
- for (let key in finalData) {
191
- if (new RegExp(pattern).test(key)) {
192
- errors.push(
193
- new ValidationError("Property is not allowed", {
194
- pointer: `${pointer}/${key}`,
195
- value: data[key],
196
- code: "PROPERTY_NOT_ALLOWED"
197
- })
198
- );
157
+ for (const key in data) {
158
+ if (regex.test(key)) {
159
+ return defineError("Property is not allowed", {
160
+ item: key,
161
+ data: data[key]
162
+ });
199
163
  }
200
164
  }
201
165
  }
202
166
  continue;
203
167
  }
204
168
 
205
- const { validator } = schema.patternProperties[pattern] as CompiledSchema;
206
- if (!validator) {
207
- continue;
169
+ const keys = Object.keys(data);
170
+ for (const key of keys) {
171
+ if (regex.test(key)) {
172
+ if ("$validate" in schema.patternProperties[pattern]) {
173
+ const error = schema.patternProperties[pattern].$validate(
174
+ data[key]
175
+ );
176
+ if (error) {
177
+ return defineError("Property is invalid", {
178
+ item: key,
179
+ cause: error,
180
+ data: data[key]
181
+ });
182
+ }
183
+ }
184
+ }
208
185
  }
186
+ }
209
187
 
210
- for (let key in finalData) {
211
- if (new RegExp(pattern).test(key)) {
212
- const validatorResult = validator(
213
- schema.patternProperties[pattern],
214
- finalData[key],
215
- `${pointer}/${key}`,
216
- schemaShieldInstance
217
- );
188
+ return;
189
+ },
218
190
 
219
- finalData[key] = validatorResult.data;
191
+ propertyNames(schema, data, defineError) {
192
+ if (!isObject(data)) {
193
+ return;
194
+ }
195
+ if (typeof schema.propertyNames === "boolean") {
196
+ if (schema.propertyNames === false && Object.keys(data).length > 0) {
197
+ return defineError("Properties are not allowed", { data });
198
+ }
199
+ }
200
+ if (isCompiledSchema(schema.propertyNames)) {
201
+ for (let key in data) {
202
+ const error = schema.propertyNames.$validate(key);
203
+ if (error) {
204
+ return defineError("Property name is invalid", {
205
+ item: key,
206
+ cause: error,
207
+ data: data[key]
208
+ });
209
+ }
210
+ }
211
+ }
212
+
213
+ return;
214
+ },
215
+
216
+ dependencies(schema, data, defineError) {
217
+ if (!isObject(data)) {
218
+ return;
219
+ }
220
+
221
+ for (const key in schema.dependencies) {
222
+ if (key in data === false) {
223
+ continue;
224
+ }
220
225
 
221
- if (!validatorResult.valid) {
222
- errors.push(...validatorResult.errors);
226
+ const dependency = schema.dependencies[key];
227
+ if (Array.isArray(dependency)) {
228
+ for (let i = 0; i < dependency.length; i++) {
229
+ if (!(dependency[i] in data)) {
230
+ return defineError("Dependency is not satisfied", {
231
+ item: i,
232
+ data: dependency[i]
233
+ });
223
234
  }
224
235
  }
236
+ continue;
237
+ }
238
+ if (typeof dependency === "boolean") {
239
+ if (dependency) {
240
+ continue;
241
+ }
242
+ return defineError("Dependency is not satisfied", { data: dependency });
243
+ }
244
+
245
+ if (typeof dependency === "string") {
246
+ if (dependency in data) {
247
+ continue;
248
+ }
249
+ return defineError("Dependency is not satisfied", { data: dependency });
250
+ }
251
+ const error = dependency.$validate(data);
252
+ if (error) {
253
+ return defineError("Dependency is not satisfied", {
254
+ cause: error,
255
+ data
256
+ });
225
257
  }
226
258
  }
227
259
 
228
- return { valid: errors.length === 0, errors, data: finalData };
229
- }
260
+ return;
261
+ },
262
+
263
+ // Required by other keywords but not used as a function itself
264
+ then: false,
265
+ else: false,
266
+ default: false,
267
+
268
+ // Not implemented yet
269
+ $ref: false,
270
+ definitions: false,
271
+ $id: false,
272
+ $schema: false,
273
+
274
+ // Metadata keywords (not used as a function)
275
+ title: false,
276
+ description: false,
277
+ $comment: false,
278
+ examples: false,
279
+ contentMediaType: false,
280
+ contentEncoding: false,
281
+
282
+ // Not supported Open API keywords
283
+ discriminator: false,
284
+ nullable: false
230
285
  };