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,204 +1,196 @@
1
- import { CompiledSchema, ValidatorFunction } from "../index";
2
- import { ValidationError, isObject } from "../utils";
1
+ import { isCompiledSchema, isObject } from "../utils";
3
2
 
4
- export const ArrayKeywords: Record<string, ValidatorFunction> = {
5
- items(schema, data, pointer, schemaShieldInstance) {
3
+ import { KeywordFunction } from "../index";
4
+
5
+ export const ArrayKeywords: Record<string, KeywordFunction> = {
6
+ items(schema, data, defineError) {
6
7
  if (!Array.isArray(data)) {
7
- return { valid: true, errors: [], data };
8
- }
9
-
10
- const errors = [];
11
- let finalData = [...data];
12
- if (Array.isArray(schema.items)) {
13
- for (let i = 0; i < schema.items.length; i++) {
14
- if (typeof schema.items[i] === "boolean") {
15
- if (schema.items[i] === false && typeof data[i] !== "undefined") {
16
- errors.push(
17
- new ValidationError("Array item is not allowed", {
18
- pointer: `${pointer}/${i}`,
19
- value: data[i],
20
- code: "ARRAY_ITEM_NOT_ALLOWED"
21
- })
22
- );
8
+ return;
9
+ }
10
+
11
+ const schemaItems = schema.items;
12
+ const dataLength = data.length;
13
+
14
+ if (typeof schemaItems === "boolean") {
15
+ if (schemaItems === false && dataLength > 0) {
16
+ return defineError("Array items are not allowed", { data });
17
+ }
18
+
19
+ return;
20
+ }
21
+
22
+ if (Array.isArray(schemaItems)) {
23
+ const schemaItemsLength = schemaItems.length;
24
+ const itemsLength = Math.min(schemaItemsLength, dataLength);
25
+ for (let i = 0; i < itemsLength; i++) {
26
+ const schemaItem = schemaItems[i];
27
+ if (typeof schemaItem === "boolean") {
28
+ if (schemaItem === false && typeof data[i] !== "undefined") {
29
+ return defineError("Array item is not allowed", {
30
+ item: i,
31
+ data: data[i]
32
+ });
23
33
  }
24
34
  continue;
25
35
  }
26
36
 
27
- const { validator } = schema.items[i] as CompiledSchema;
28
- if (!validator) {
29
- continue;
37
+ if (isCompiledSchema(schemaItem)) {
38
+ const error = schemaItem.$validate(data[i]);
39
+ if (error) {
40
+ return defineError("Array item is invalid", {
41
+ item: i,
42
+ cause: error,
43
+ data: data[i]
44
+ });
45
+ }
30
46
  }
31
- const validatorResult = validator(
32
- schema.items[i],
33
- finalData[i],
34
- `${pointer}/${i}`,
35
- schemaShieldInstance
36
- );
47
+ }
37
48
 
38
- finalData[i] = validatorResult.data;
49
+ return;
50
+ }
39
51
 
40
- if (!validatorResult.valid) {
41
- errors.push(...validatorResult.errors);
52
+ if (isCompiledSchema(schemaItems)) {
53
+ for (let i = 0; i < dataLength; i++) {
54
+ const error = schemaItems.$validate(data[i]);
55
+ if (error) {
56
+ return defineError("Array item is invalid", {
57
+ item: i,
58
+ cause: error,
59
+ data: data[i]
60
+ });
42
61
  }
43
62
  }
44
- } else if (typeof schema.items === "boolean") {
45
- if (schema.items === false && data.length > 0) {
46
- errors.push(
47
- new ValidationError("Array is not allowed", {
48
- pointer,
49
- value: data,
50
- code: "ARRAY_NOT_ALLOWED"
51
- })
52
- );
53
- }
54
- } else {
55
- const { validator } = schema.items as CompiledSchema;
56
- if (!validator) {
57
- return { valid: true, errors: [], data };
58
- }
63
+ }
59
64
 
60
- for (let i = 0; i < finalData.length; i++) {
61
- const validatorErrors = validator(
62
- schema.items,
63
- finalData[i],
64
- `${pointer}/${i}`,
65
- schemaShieldInstance
66
- );
65
+ return;
66
+ },
67
67
 
68
- finalData[i] = validatorErrors.data;
68
+ elements(schema, data, defineError) {
69
+ if (!Array.isArray(data) || !isCompiledSchema(schema.elements)) {
70
+ return;
71
+ }
69
72
 
70
- if (!validatorErrors.valid) {
71
- errors.push(...validatorErrors.errors);
72
- }
73
+ for (let i = 0; i < data.length; i++) {
74
+ const error = schema.elements.$validate(data[i]);
75
+ if (error) {
76
+ return defineError("Array item is invalid", {
77
+ item: i,
78
+ cause: error,
79
+ data: data[i]
80
+ });
73
81
  }
74
82
  }
75
83
 
76
- return { valid: errors.length === 0, errors, data: finalData };
84
+ return;
77
85
  },
78
86
 
79
- minItems(schema, data, pointer) {
87
+ minItems(schema, data, defineError) {
80
88
  if (!Array.isArray(data) || data.length >= schema.minItems) {
81
- return { valid: true, errors: [], data };
82
- }
83
-
84
- return {
85
- valid: false,
86
- errors: [
87
- new ValidationError("Array is too short", {
88
- pointer,
89
- value: data,
90
- code: "ARRAY_TOO_SHORT"
91
- })
92
- ],
93
- data
94
- };
89
+ return;
90
+ }
91
+
92
+ return defineError("Array is too short", { data });
95
93
  },
96
94
 
97
- maxItems(schema, data, pointer) {
95
+ maxItems(schema, data, defineError) {
98
96
  if (!Array.isArray(data) || data.length <= schema.maxItems) {
99
- return { valid: true, errors: [], data };
100
- }
101
-
102
- return {
103
- valid: false,
104
- errors: [
105
- new ValidationError("Array is too long", {
106
- pointer,
107
- value: data,
108
- code: "ARRAY_TOO_LONG"
109
- })
110
- ],
111
- data
112
- };
97
+ return;
98
+ }
99
+
100
+ return defineError("Array is too long", { data });
113
101
  },
114
102
 
115
- additionalItems(schema, data, pointer, schemaShieldInstance) {
103
+ additionalItems(schema, data, defineError) {
116
104
  if (!Array.isArray(data) || !schema.items || !Array.isArray(schema.items)) {
117
- return { valid: true, errors: [], data };
105
+ return;
118
106
  }
119
107
 
120
108
  if (schema.additionalItems === false) {
121
109
  if (data.length > schema.items.length) {
122
- return {
123
- valid: false,
124
- errors: [
125
- new ValidationError("Array has too many items", {
126
- pointer,
127
- value: data,
128
- code: "ARRAY_TOO_MANY_ITEMS"
129
- })
130
- ],
131
- data
132
- };
110
+ return defineError("Array is too long", { data });
133
111
  }
112
+ return;
113
+ }
134
114
 
135
- return { valid: true, errors: [], data };
136
- }
137
-
138
- const errors = [];
139
- let finalData = [...data];
140
- if (typeof schema.additionalItems === "object") {
141
- for (let i = schema.items.length; i < finalData.length; i++) {
142
- const { validator } = schema.additionalItems as CompiledSchema;
143
- const validatorResult = validator(
144
- schema.additionalItems,
145
- finalData[i],
146
- `${pointer}/${i}`,
147
- schemaShieldInstance
148
- );
149
- if (!validatorResult.valid) {
150
- errors.push(...validatorResult.errors);
115
+ if (isObject(schema.additionalItems)) {
116
+ if (isCompiledSchema(schema.additionalItems)) {
117
+ for (let i = schema.items.length; i < data.length; i++) {
118
+ const error = schema.additionalItems.$validate(data[i]);
119
+ if (error) {
120
+ return defineError("Array item is invalid", {
121
+ item: i,
122
+ cause: error,
123
+ data: data[i]
124
+ });
125
+ }
151
126
  }
152
- finalData[i] = validatorResult.data;
127
+ return;
153
128
  }
129
+
130
+ return;
154
131
  }
155
132
 
156
- return { valid: errors.length === 0, errors, data: finalData };
133
+ return;
157
134
  },
158
135
 
159
- uniqueItems(schema, data, pointer) {
136
+ uniqueItems(schema, data, defineError) {
160
137
  if (!Array.isArray(data) || !schema.uniqueItems) {
161
- return { valid: true, errors: [], data };
138
+ return;
162
139
  }
163
140
 
164
141
  const unique = new Set();
165
142
 
166
143
  for (const item of data) {
167
- let itemStr = item;
144
+ let itemStr;
168
145
 
169
146
  // Change string to "string" to avoid false positives
170
147
  if (typeof item === "string") {
171
- itemStr = `"${item}"`;
172
-
148
+ itemStr = `s:${item}`;
173
149
  // Sort object keys to avoid false positives
174
150
  } else if (isObject(item)) {
175
- const keys = Object.keys(item).sort();
176
- const sorted = {};
177
- for (let i = 0; i < keys.length; i++) {
178
- sorted[keys[i]] = item[keys[i]];
179
- }
180
- itemStr = JSON.stringify(sorted);
151
+ itemStr = `o:${JSON.stringify(
152
+ Object.fromEntries(
153
+ Object.entries(item).sort(([a], [b]) => a.localeCompare(b))
154
+ )
155
+ )}`;
181
156
  } else if (Array.isArray(item)) {
182
157
  itemStr = JSON.stringify(item);
158
+ } else {
159
+ itemStr = String(item);
183
160
  }
184
161
 
185
162
  if (unique.has(itemStr)) {
186
- return {
187
- valid: false,
188
- errors: [
189
- new ValidationError("Array items are not unique", {
190
- pointer,
191
- value: data,
192
- code: "ARRAY_ITEMS_NOT_UNIQUE"
193
- })
194
- ],
195
- data
196
- };
197
- } else {
198
- unique.add(itemStr);
163
+ return defineError("Array items are not unique", { data: item });
164
+ }
165
+ unique.add(itemStr);
166
+ }
167
+
168
+ return;
169
+ },
170
+
171
+ contains(schema, data, defineError) {
172
+ if (!Array.isArray(data)) {
173
+ return;
174
+ }
175
+ if (typeof schema.contains === "boolean") {
176
+ if (schema.contains) {
177
+ if (data.length === 0) {
178
+ return defineError("Array must contain at least one item", { data });
179
+ }
180
+ return;
181
+ }
182
+
183
+ return defineError("Array must not contain any items", { data });
184
+ }
185
+
186
+ for (let i = 0; i < data.length; i++) {
187
+ const error = schema.contains.$validate(data[i]);
188
+ if (!error) {
189
+ return;
199
190
  }
191
+ continue;
200
192
  }
201
193
 
202
- return { valid: true, errors: [], data };
194
+ return defineError("Array must contain at least one item", { data });
203
195
  }
204
196
  };
@@ -1,79 +1,95 @@
1
- import { ValidationError } from "../utils";
2
- import { ValidatorFunction } from "../index";
1
+ import { KeywordFunction } from "../index";
2
+ import { areCloseEnough } from "../utils";
3
3
 
4
- export const NumberKeywords: Record<string, ValidatorFunction> = {
5
- minimum(schema, data, pointer) {
4
+ export const NumberKeywords: Record<string, KeywordFunction> = {
5
+ minimum(schema, data, defineError, instance) {
6
6
  if (typeof data !== "number") {
7
- return { valid: true, errors: [], data };
7
+ return;
8
8
  }
9
9
 
10
- const min = schema.exclusiveMinimum
11
- ? schema.minimum + 1e-15
12
- : schema.minimum;
13
-
14
- const valid = data >= min;
15
-
16
- return {
17
- valid,
18
- errors: valid
19
- ? []
20
- : [
21
- new ValidationError("Number is too small", {
22
- pointer,
23
- value: data,
24
- code: "NUMBER_TOO_SMALL"
25
- })
26
- ],
27
- data
28
- };
10
+ let min = schema.minimum;
11
+ if (typeof schema.exclusiveMinimum === "number") {
12
+ min = schema.exclusiveMinimum + 1e-15;
13
+ } else if (schema.exclusiveMinimum === true) {
14
+ min += 1e-15;
15
+ }
16
+
17
+ if (data < min) {
18
+ return defineError("Value is less than the minimum", { data });
19
+ }
20
+
21
+ return;
29
22
  },
30
23
 
31
- maximum(schema, data, pointer) {
24
+ maximum(schema, data, defineError, instance) {
32
25
  if (typeof data !== "number") {
33
- return { valid: true, errors: [], data };
26
+ return;
34
27
  }
35
28
 
36
- const max = schema.exclusiveMaximum
37
- ? schema.maximum - 1e-15
38
- : schema.maximum;
39
-
40
- const valid = data <= max;
41
-
42
- return {
43
- valid,
44
- errors: valid
45
- ? []
46
- : [
47
- new ValidationError("Number is too large", {
48
- pointer,
49
- value: data,
50
- code: "NUMBER_TOO_LARGE"
51
- })
52
- ],
53
- data
54
- };
29
+ let max = schema.maximum;
30
+ if (typeof schema.exclusiveMaximum === "number") {
31
+ max = schema.exclusiveMaximum - 1e-15;
32
+ } else if (schema.exclusiveMaximum === true) {
33
+ max -= 1e-15;
34
+ }
35
+
36
+ if (data > max) {
37
+ return defineError("Value is greater than the maximum", { data });
38
+ }
39
+
40
+ return;
55
41
  },
56
42
 
57
- multipleOf(schema, data, pointer) {
43
+ multipleOf(schema, data, defineError, instance) {
58
44
  if (typeof data !== "number") {
59
- return { valid: true, errors: [], data };
45
+ return;
60
46
  }
61
47
 
62
48
  const quotient = data / schema.multipleOf;
63
- const areMultiples = Math.abs(quotient - Math.round(quotient)) < 1e-15;
64
-
65
- return {
66
- valid: areMultiples,
67
- errors: areMultiples
68
- ? []
69
- : [
70
- new ValidationError("Number is not a multiple of", {
71
- pointer,
72
- value: data,
73
- code: "NUMBER_NOT_MULTIPLE_OF"
74
- })
75
- ],
76
- data
77
- };
49
+
50
+ if (!isFinite(quotient)) {
51
+ return;
52
+ }
53
+
54
+ if (!areCloseEnough(quotient, Math.round(quotient))) {
55
+ return defineError("Value is not a multiple of the multipleOf", { data });
56
+ }
57
+
58
+ return;
59
+ },
60
+
61
+ exclusiveMinimum(schema, data, defineError, instance) {
62
+ if (
63
+ typeof data !== "number" ||
64
+ typeof schema.exclusiveMinimum !== "number" ||
65
+ "minimum" in schema
66
+ ) {
67
+ return;
68
+ }
69
+
70
+ if (data <= schema.exclusiveMinimum + 1e-15) {
71
+ return defineError("Value is less than or equal to the exclusiveMinimum");
72
+ }
73
+
74
+ return;
75
+ },
76
+
77
+ exclusiveMaximum(schema, data, defineError, instance) {
78
+ if (
79
+ typeof data !== "number" ||
80
+ typeof schema.exclusiveMaximum !== "number" ||
81
+ "maximum" in schema
82
+ ) {
83
+ return;
84
+ }
85
+
86
+ if (data >= schema.exclusiveMaximum) {
87
+ return defineError(
88
+ "Value is greater than or equal to the exclusiveMaximum",
89
+ { data }
90
+ );
91
+ }
92
+
93
+ return;
78
94
  }
79
95
  };