schema-shield 0.0.2 → 0.0.4

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,248 +1,190 @@
1
- import { CompiledSchema, ValidatorFunction } from "../index";
2
- import { ValidationError, isObject } from "../utils";
3
-
4
- export const OtherKeywords: Record<string, ValidatorFunction> = {
5
- nullable(schema, data, pointer) {
6
- if (schema.nullable && data !== null) {
7
- return {
8
- valid: false,
9
- errors: [
10
- new ValidationError("Value must be null to be empty", {
11
- pointer,
12
- value: data,
13
- code: "VALUE_NOT_NULL"
14
- })
15
- ],
16
- data
17
- };
18
- }
1
+ import { deepEqual, isCompiledSchema, isObject } from "../utils";
19
2
 
20
- return { valid: true, errors: [], data };
21
- },
3
+ import { KeywordFunction } from "../index";
22
4
 
23
- oneOf(schema, data, pointer, schemaShieldInstance) {
24
- const errors = [];
25
- let validCount = 0;
26
- let finalData = data;
27
- for (let i = 0; i < schema.oneOf.length; i++) {
28
- if (isObject(schema.oneOf[i])) {
29
- const { validator } = schema.oneOf[i] as CompiledSchema;
30
- if (!validator) {
31
- validCount++;
32
- continue;
33
- }
34
- const validationResult = validator(
35
- schema.oneOf[i],
36
- finalData,
37
- pointer,
38
- schemaShieldInstance
39
- );
40
- if (validationResult.valid) {
41
- validCount++;
42
- } else {
43
- errors.push(...validationResult.errors);
44
- }
45
- finalData = validationResult.data;
46
- } else {
47
- if (typeof schema.oneOf[i] === "boolean") {
48
- if (Boolean(data) === schema.oneOf[i]) {
49
- validCount++;
50
- }
51
- continue;
52
- }
5
+ export const OtherKeywords: Record<string, KeywordFunction> = {
6
+ enum(schema, data, defineError) {
7
+ // Check if data is an array or an object
8
+ const isArray = Array.isArray(data);
9
+ const isObject = typeof data === "object" && data !== null;
53
10
 
54
- if (data === schema.oneOf[i]) {
55
- validCount++;
56
- }
11
+ for (let i = 0; i < schema.enum.length; i++) {
12
+ const enumItem = schema.enum[i];
13
+
14
+ // Simple equality check
15
+ if (enumItem === data) {
16
+ return;
57
17
  }
58
- }
59
18
 
60
- if (validCount === 1) {
61
- return { valid: true, errors: [], data: finalData };
19
+ // If data is an array or an object, check for deep equality
20
+ if (
21
+ (isArray && Array.isArray(enumItem)) ||
22
+ (isObject && typeof enumItem === "object" && enumItem !== null)
23
+ ) {
24
+ if (deepEqual(enumItem, data)) {
25
+ return;
26
+ }
27
+ }
62
28
  }
63
29
 
64
- return {
65
- valid: false,
66
- errors: [
67
- new ValidationError(`Value must match exactly one schema in oneOf`, {
68
- pointer,
69
- value: data,
70
- code: "VALUE_DOES_NOT_MATCH_ONE_OF"
71
- })
72
- ],
73
- data: finalData
74
- };
30
+ return defineError("Value is not one of the allowed values", { data });
75
31
  },
76
32
 
77
- allOf(schema, data, pointer, schemaShieldInstance) {
78
- const errors = [];
79
- let finalData = data;
33
+ allOf(schema, data, defineError) {
80
34
  for (let i = 0; i < schema.allOf.length; i++) {
81
35
  if (isObject(schema.allOf[i])) {
82
- const { validator } = schema.allOf[i] as CompiledSchema;
83
- if (!validator) {
84
- continue;
85
- }
86
-
87
- const validatorResult = validator(
88
- schema.allOf[i],
89
- finalData,
90
- pointer,
91
- schemaShieldInstance
92
- );
93
-
94
- if (!validatorResult.valid) {
95
- errors.push(...validatorResult.errors);
96
- }
97
-
98
- finalData = validatorResult.data;
99
- } else {
100
- if (typeof schema.allOf[i] === "boolean") {
101
- if (Boolean(data) !== schema.allOf[i]) {
102
- errors.push(
103
- new ValidationError(`Value must match all schemas in allOf`, {
104
- pointer,
105
- value: data,
106
- code: "VALUE_DOES_NOT_MATCH_ALL_OF"
107
- })
108
- );
36
+ if ("$validate" in schema.allOf[i]) {
37
+ const error = schema.allOf[i].$validate(data);
38
+ if (error) {
39
+ return defineError("Value is not valid", { cause: error, data });
109
40
  }
110
- continue;
111
41
  }
42
+ continue;
43
+ }
112
44
 
113
- if (data !== schema.allOf[i]) {
114
- errors.push(
115
- new ValidationError(`Value must match all schemas in allOf`, {
116
- pointer,
117
- value: data,
118
- code: "VALUE_DOES_NOT_MATCH_ALL_OF"
119
- })
120
- );
45
+ if (typeof schema.allOf[i] === "boolean") {
46
+ if (Boolean(data) !== schema.allOf[i]) {
47
+ return defineError("Value is not valid", { data });
121
48
  }
49
+ continue;
50
+ }
51
+
52
+ if (data !== schema.allOf[i]) {
53
+ return defineError("Value is not valid", { data });
122
54
  }
123
55
  }
124
56
 
125
- return { valid: errors.length === 0, errors, data: finalData };
57
+ return;
126
58
  },
127
59
 
128
- anyOf(schema, data, pointer, schemaShieldInstance) {
129
- let finalData = data;
130
-
60
+ anyOf(schema, data, defineError) {
131
61
  for (let i = 0; i < schema.anyOf.length; i++) {
132
62
  if (isObject(schema.anyOf[i])) {
133
- const { validator } = schema.anyOf[i] as CompiledSchema;
134
- if (!validator) {
135
- return { valid: true, errors: [], data };
136
- }
137
- const validationResult = validator(
138
- schema.anyOf[i],
139
- finalData,
140
- pointer,
141
- schemaShieldInstance
142
- );
143
- finalData = validationResult.data;
144
- if (validationResult.valid) {
145
- return { valid: true, errors: [], data: finalData };
63
+ if ("$validate" in schema.anyOf[i]) {
64
+ const error = schema.anyOf[i].$validate(data);
65
+ if (!error) {
66
+ return;
67
+ }
68
+ continue;
146
69
  }
70
+ return;
147
71
  } else {
148
72
  if (typeof schema.anyOf[i] === "boolean") {
149
73
  if (Boolean(data) === schema.anyOf[i]) {
150
- return { valid: true, errors: [], data: finalData };
74
+ return;
151
75
  }
152
76
  }
153
77
 
154
78
  if (data === schema.anyOf[i]) {
155
- return { valid: true, errors: [], data: finalData };
79
+ return;
156
80
  }
157
81
  }
158
82
  }
159
83
 
160
- return {
161
- valid: false,
162
- errors: [
163
- new ValidationError(`Value must match at least one schema in anyOf`, {
164
- pointer,
165
- value: data,
166
- code: "VALUE_DOES_NOT_MATCH_ANY_OF"
167
- })
168
- ],
169
- data
170
- };
84
+ return defineError("Value is not valid", { data });
171
85
  },
172
86
 
173
- dependencies(schema, data, pointer, schemaShieldInstance) {
174
- if (!isObject(data)) {
175
- return { valid: true, errors: [], data };
176
- }
177
-
178
- const errors = [];
179
- let finalData = data;
180
- for (const key in schema.dependencies) {
181
- if (key in data === false) {
182
- continue;
183
- }
184
-
185
- const dependency = schema.dependencies[key];
186
- if (Array.isArray(dependency)) {
187
- for (let i = 0; i < dependency.length; i++) {
188
- if (!(dependency[i] in data)) {
189
- errors.push(
190
- new ValidationError(`Dependency ${dependency[i]} is missing`, {
191
- pointer,
192
- value: data,
193
- code: "DEPENDENCY_MISSING"
194
- })
195
- );
87
+ oneOf(schema, data, defineError) {
88
+ let validCount = 0;
89
+ for (let i = 0; i < schema.oneOf.length; i++) {
90
+ if (isObject(schema.oneOf[i])) {
91
+ if ("$validate" in schema.oneOf[i]) {
92
+ const error = schema.oneOf[i].$validate(data);
93
+ if (!error) {
94
+ validCount++;
196
95
  }
96
+ continue;
197
97
  }
98
+ validCount++;
198
99
  continue;
199
- }
200
-
201
- if (typeof dependency === "boolean") {
202
- if (dependency) {
100
+ } else {
101
+ if (typeof schema.oneOf[i] === "boolean") {
102
+ if (Boolean(data) === schema.oneOf[i]) {
103
+ validCount++;
104
+ }
203
105
  continue;
204
106
  }
205
- errors.push(
206
- new ValidationError(`Dependency ${key} is missing`, {
207
- pointer,
208
- value: data,
209
- code: "DEPENDENCY_MISSING"
210
- })
211
- );
212
- continue;
107
+
108
+ if (data === schema.oneOf[i]) {
109
+ validCount++;
110
+ }
213
111
  }
112
+ }
214
113
 
215
- if (typeof dependency === "string") {
216
- if (dependency in data) {
217
- continue;
114
+ if (validCount === 1) {
115
+ return;
116
+ }
117
+
118
+ return defineError("Value is not valid", { data });
119
+ },
120
+
121
+ const(schema, data, defineError) {
122
+ if (
123
+ data === schema.const ||
124
+ (isObject(data) &&
125
+ isObject(schema.const) &&
126
+ deepEqual(data, schema.const)) ||
127
+ (Array.isArray(data) &&
128
+ Array.isArray(schema.const) &&
129
+ deepEqual(data, schema.const))
130
+ ) {
131
+ return;
132
+ }
133
+ return defineError("Value is not valid", { data });
134
+ },
135
+
136
+ if(schema, data, defineError) {
137
+ if ("then" in schema === false && "else" in schema === false) {
138
+ return;
139
+ }
140
+ if (typeof schema.if === "boolean") {
141
+ if (schema.if) {
142
+ if (isCompiledSchema(schema.then)) {
143
+ return schema.then.$validate(data);
218
144
  }
219
- errors.push(
220
- new ValidationError(`Dependency ${dependency} is missing`, {
221
- pointer,
222
- value: data,
223
- code: "DEPENDENCY_MISSING"
224
- })
225
- );
226
- continue;
145
+ } else if (isCompiledSchema(schema.else)) {
146
+ return schema.else.$validate(data);
227
147
  }
148
+ return;
149
+ }
228
150
 
229
- const { validator } = dependency as CompiledSchema;
230
- if (!validator) {
231
- continue;
151
+ if (!isCompiledSchema(schema.if)) {
152
+ return;
153
+ }
154
+
155
+ const error = schema.if.$validate(data);
156
+ if (!error) {
157
+ if (isCompiledSchema(schema.then)) {
158
+ return schema.then.$validate(data);
159
+ }
160
+ return;
161
+ } else {
162
+ if (isCompiledSchema(schema.else)) {
163
+ return schema.else.$validate(data);
164
+ }
165
+ return;
166
+ }
167
+ },
168
+
169
+ not(schema, data, defineError) {
170
+ if (typeof schema.not === "boolean") {
171
+ if (schema.not) {
172
+ return defineError("Value is not valid", { data });
232
173
  }
174
+ return;
175
+ }
233
176
 
234
- const validatorResult = validator(
235
- dependency,
236
- finalData,
237
- pointer,
238
- schemaShieldInstance
239
- );
240
- if (!validatorResult.valid) {
241
- errors.push(...validatorResult.errors);
177
+ if (isObject(schema.not)) {
178
+ if ("$validate" in schema.not) {
179
+ const error = schema.not.$validate(data);
180
+ if (!error) {
181
+ return defineError("Value is not valid", { cause: error, data });
182
+ }
183
+ return;
242
184
  }
243
- finalData = validatorResult.data;
185
+ return defineError("Value is not valid", { data });
244
186
  }
245
187
 
246
- return { valid: errors.length === 0, errors, data: finalData };
188
+ return defineError("Value is not valid", { data });
247
189
  }
248
190
  };
@@ -1,165 +1,52 @@
1
- import { ValidationError, deepEqual } from "../utils";
1
+ import { KeywordFunction } from "../index";
2
2
 
3
- import { ValidatorFunction } from "../index";
4
-
5
- export const StringKeywords: Record<string, ValidatorFunction> = {
6
- minLength(schema, data, pointer) {
3
+ export const StringKeywords: Record<string, KeywordFunction> = {
4
+ minLength(schema, data, defineError) {
7
5
  if (typeof data !== "string" || data.length >= schema.minLength) {
8
- return { valid: true, errors: [], data };
6
+ return;
9
7
  }
10
8
 
11
- return {
12
- valid: false,
13
- errors: [
14
- new ValidationError("String is too short", {
15
- pointer,
16
- value: data,
17
- code: "STRING_TOO_SHORT"
18
- })
19
- ],
20
- data
21
- };
9
+ return defineError("Value is shorter than the minimum length", { data });
22
10
  },
23
11
 
24
- maxLength(schema, data, pointer) {
12
+ maxLength(schema, data, defineError) {
25
13
  if (typeof data !== "string" || data.length <= schema.maxLength) {
26
- return { valid: true, errors: [], data };
14
+ return;
27
15
  }
28
16
 
29
- return {
30
- valid: false,
31
- errors: [
32
- new ValidationError("String is too long", {
33
- pointer,
34
- value: data,
35
- code: "STRING_TOO_LONG"
36
- })
37
- ],
38
- data
39
- };
17
+ return defineError("Value is longer than the maximum length", { data });
40
18
  },
41
19
 
42
- pattern(schema, data, pointer) {
20
+ pattern(schema, data, defineError) {
43
21
  if (typeof data !== "string") {
44
- return { valid: true, errors: [], data };
22
+ return;
45
23
  }
46
24
 
47
- const patternRegexp =
48
- typeof schema.pattern === "string"
49
- ? new RegExp(schema.pattern)
50
- : schema.pattern;
25
+ const patternRegexp = new RegExp(schema.pattern, "u");
51
26
 
52
27
  if (patternRegexp instanceof RegExp === false) {
53
- return {
54
- valid: false,
55
- errors: [
56
- new ValidationError("Pattern is not a valid regular expression", {
57
- pointer,
58
- value: data,
59
- code: "PATTERN_IS_NOT_REGEXP"
60
- })
61
- ],
62
- data
63
- };
28
+ return defineError("Invalid regular expression", { data });
64
29
  }
65
30
 
66
- const valid = patternRegexp.test(data);
67
-
68
- return {
69
- valid,
70
- errors: valid
71
- ? []
72
- : [
73
- new ValidationError("String does not match pattern", {
74
- pointer,
75
- value: data,
76
- code: "STRING_DOES_NOT_MATCH_PATTERN"
77
- })
78
- ],
79
- data
80
- };
81
- },
82
-
83
- format(schema, data, pointer, formatInstance) {
84
- if (typeof data !== "string") {
85
- return { valid: true, errors: [], data };
31
+ if (patternRegexp.test(data)) {
32
+ return;
86
33
  }
87
34
 
88
- const formatValidate = formatInstance.formats.get(schema.format);
89
- if (!formatValidate) {
90
- return {
91
- valid: false,
92
- errors: [
93
- new ValidationError(`Unknown format ${schema.format}`, {
94
- pointer,
95
- value: data,
96
- code: "UNKNOWN_FORMAT"
97
- })
98
- ],
99
- data
100
- };
101
- }
102
-
103
- const valid = formatValidate(data);
104
-
105
- return {
106
- valid,
107
- errors: valid
108
- ? []
109
- : [
110
- new ValidationError(
111
- `String does not match format ${schema.format}`,
112
- {
113
- pointer,
114
- value: data,
115
- code: "STRING_DOES_NOT_MATCH_FORMAT"
116
- }
117
- )
118
- ],
119
- data
120
- };
35
+ return defineError("Value does not match the pattern", { data });
121
36
  },
122
37
 
123
- enum(schema, data, pointer) {
124
- // Simple equality check
125
- for (let i = 0; i < schema.enum.length; i++) {
126
- if (schema.enum[i] === data) {
127
- return { valid: true, errors: [], data };
128
- }
129
- }
130
-
131
- // If is an array check for a deep equality
132
- if (Array.isArray(data)) {
133
- for (let i = 0; i < schema.enum.length; i++) {
134
- if (Array.isArray(schema.enum[i])) {
135
- if (deepEqual(schema.enum[i], data)) {
136
- return { valid: true, errors: [], data };
137
- }
138
- }
139
- }
38
+ // Take into account that if we receive a format that is not defined, we
39
+ // will not throw an error, we just ignore it.
40
+ format(schema, data, defineError, instance) {
41
+ if (typeof data !== "string") {
42
+ return;
140
43
  }
141
44
 
142
- // If is an object check for a deep equality
143
- if (typeof data === "object" && data !== null) {
144
- for (let i = 0; i < schema.enum.length; i++) {
145
- if (typeof schema.enum[i] === "object" && schema.enum[i] !== null) {
146
- if (deepEqual(schema.enum[i], data)) {
147
- return { valid: true, errors: [], data };
148
- }
149
- }
150
- }
45
+ const formatValidate = instance.getFormat(schema.format);
46
+ if (!formatValidate || formatValidate(data)) {
47
+ return;
151
48
  }
152
49
 
153
- return {
154
- valid: false,
155
- errors: [
156
- new ValidationError(`Value must be one of ${schema.enum.join(", ")}`, {
157
- pointer,
158
- value: data,
159
- code: "VALUE_NOT_IN_ENUM"
160
- })
161
- ],
162
- data
163
- };
50
+ return defineError("Value does not match the format", { data });
164
51
  }
165
52
  };
package/lib/keywords.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ArrayKeywords } from "./keywords/array-keywords";
2
+ import { KeywordFunction } from "./index";
2
3
  import { NumberKeywords } from "./keywords/number-keywords";
3
4
  import { ObjectKeywords } from "./keywords/object-keywords";
4
5
  import { OtherKeywords } from "./keywords/other-keywords";
5
6
  import { StringKeywords } from "./keywords/string-keywords";
6
- import { ValidatorFunction } from "./index";
7
7
 
8
- export const keywords: Record<string, ValidatorFunction> = {
8
+ export const keywords: Record<string, KeywordFunction | false> = {
9
9
  ...ObjectKeywords,
10
10
  ...ArrayKeywords,
11
11
  ...StringKeywords,