@aeriajs/validation 0.0.125 → 0.0.127

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.
@@ -3,13 +3,12 @@ import { Result } from '@aeriajs/types';
3
3
  import { ValidationErrorCode } from '@aeriajs/types';
4
4
  export type ValidateOptions = {
5
5
  tolerateExtraneous?: boolean;
6
- filterOutExtraneous?: boolean;
7
6
  throwOnError?: boolean;
8
7
  coerce?: boolean;
9
8
  parentProperty?: Omit<Description, '$id'> | Property;
10
9
  };
11
10
  export declare const makeValidationError: <TValidationError extends ValidationError>(error: TValidationError) => TValidationError;
12
- export declare const validateProperty: <TWhat>(propName: string, what: TWhat, property: Property | undefined, options?: ValidateOptions) => Result.Either<PropertyValidationError | ValidationError, unknown>;
11
+ export declare const validateProperty: <TWhat>(what: TWhat, property: Property | undefined, options?: ValidateOptions) => Result.Either<PropertyValidationError | ValidationError, unknown>;
13
12
  export declare const validateWholeness: (what: Record<string, unknown>, schema: Omit<JsonSchema, "$id">) => {
14
13
  code: ValidationErrorCode.MissingProperties;
15
14
  errors: {
package/dist/validate.js CHANGED
@@ -4,11 +4,6 @@ exports.validator = exports.validate = exports.validateWholeness = exports.valid
4
4
  const types_1 = require("@aeriajs/types");
5
5
  const common_1 = require("@aeriajs/common");
6
6
  const types_2 = require("@aeriajs/types");
7
- const getValueType = (value) => {
8
- return Array.isArray(value)
9
- ? 'array'
10
- : typeof value;
11
- };
12
7
  const getPropertyType = (property) => {
13
8
  if ('type' in property) {
14
9
  if ('format' in property && property.format) {
@@ -26,9 +21,9 @@ const getPropertyType = (property) => {
26
21
  if ('const' in property) {
27
22
  return typeof property.const;
28
23
  }
29
- if ('$ref' in property
30
- || 'properties' in property
31
- || 'additionalProperties' in property) {
24
+ if ('properties' in property
25
+ || 'additionalProperties' in property
26
+ || '$ref' in property) {
32
27
  return 'object';
33
28
  }
34
29
  };
@@ -42,13 +37,13 @@ const makeValidationError = (error) => {
42
37
  return error;
43
38
  };
44
39
  exports.makeValidationError = makeValidationError;
45
- const validateProperty = (propName, what, property, options = {}) => {
40
+ const validateProperty = (what, property, options = {}) => {
46
41
  if (!property) {
47
42
  if (options.parentProperty && 'additionalProperties' in options.parentProperty && options.parentProperty.additionalProperties) {
48
- if (options.filterOutExtraneous) {
49
- return types_1.Result.result(undefined);
43
+ if (options.parentProperty.additionalProperties === true) {
44
+ return types_1.Result.result(what);
50
45
  }
51
- return types_1.Result.result(what);
46
+ return (0, exports.validateProperty)(what, options.parentProperty.additionalProperties);
52
47
  }
53
48
  if (options.tolerateExtraneous) {
54
49
  return types_1.Result.result(undefined);
@@ -62,9 +57,10 @@ const validateProperty = (propName, what, property, options = {}) => {
62
57
  return types_1.Result.result(undefined);
63
58
  }
64
59
  const expectedType = getPropertyType(property);
65
- const actualType = getValueType(what);
60
+ const actualType = Array.isArray(what)
61
+ ? 'array'
62
+ : typeof what;
66
63
  if (actualType !== expectedType
67
- && !(('items' in property || 'enum' in property) && actualType === 'array')
68
64
  && !(actualType === 'number' && expectedType === 'integer')) {
69
65
  if (expectedType === 'datetime' && what instanceof Date) {
70
66
  return types_1.Result.result(what);
@@ -96,89 +92,85 @@ const validateProperty = (propName, what, property, options = {}) => {
96
92
  got: actualType,
97
93
  }));
98
94
  }
99
- if ('properties' in property) {
100
- return (0, exports.validate)(what, property, options);
101
- }
102
- if ('enum' in property && property.enum.length === 0) {
103
- return types_1.Result.result(what);
104
- }
105
- if ('const' in property) {
106
- if (what !== property.const) {
107
- return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.Unmatching, {
108
- expected: property.const,
109
- got: what,
110
- }));
111
- }
112
- return types_1.Result.result(what);
113
- }
114
- if ('items' in property) {
115
- if (!Array.isArray(what)) {
116
- return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.Unmatching, {
117
- expected: expectedType,
118
- got: actualType,
119
- }));
120
- }
121
- if (property.minItems) {
122
- if (what.length < property.minItems) {
123
- return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.MoreItemsExpected));
124
- }
125
- }
126
- if (property.maxItems) {
127
- if (what.length > property.maxItems) {
128
- return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.LessItemsExpected));
129
- }
130
- }
131
- let i = 0;
132
- for (const elem of what) {
133
- const { error } = (0, exports.validateProperty)(propName, elem, property.items, options);
134
- if (error) {
135
- if ('errors' in error) {
136
- continue;
137
- }
138
- error.index = i;
139
- return types_1.Result.error(error);
140
- }
141
- i++;
142
- }
143
- }
144
- else if ('type' in property) {
95
+ if ('type' in property) {
145
96
  switch (property.type) {
146
- case 'number':
147
97
  case 'integer': {
98
+ if (!Number.isInteger(what)) {
99
+ return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.NumericConstraint, {
100
+ expected: 'integer',
101
+ got: 'invalid_number',
102
+ }));
103
+ }
104
+ }
105
+ case 'number': {
148
106
  if (typeof what !== 'number') {
149
107
  return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.Unmatching, {
150
108
  expected: expectedType,
151
109
  got: actualType,
152
110
  }));
153
111
  }
154
- if (property.type === 'integer') {
155
- if (!Number.isInteger(what)) {
156
- return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.NumericConstraint, {
157
- expected: 'integer',
158
- got: 'invalid_number',
159
- }));
160
- }
161
- }
162
- if ((property.maximum && property.maximum < what)
163
- || (property.minimum && property.minimum > what)
164
- || (property.exclusiveMaximum && property.exclusiveMaximum <= what)
165
- || (property.exclusiveMinimum && property.exclusiveMinimum >= what)) {
112
+ if ((typeof property.maximum === 'number' && property.maximum < what)
113
+ || (typeof property.minimum === 'number' && property.minimum > what)
114
+ || (typeof property.exclusiveMaximum === 'number' && property.exclusiveMaximum <= what)
115
+ || (typeof property.exclusiveMinimum === 'number' && property.exclusiveMinimum >= what)) {
166
116
  return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.NumericConstraint, {
167
117
  expected: 'number',
168
118
  got: 'invalid_number',
169
119
  }));
170
120
  }
121
+ break;
122
+ }
123
+ case 'object': {
124
+ return (0, exports.validate)(what, property, options);
125
+ }
126
+ case 'array': {
127
+ if (!Array.isArray(what)) {
128
+ return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.Unmatching, {
129
+ expected: expectedType,
130
+ got: actualType,
131
+ }));
132
+ }
133
+ if (property.minItems) {
134
+ if (what.length < property.minItems) {
135
+ return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.MoreItemsExpected));
136
+ }
137
+ }
138
+ if (property.maxItems) {
139
+ if (what.length > property.maxItems) {
140
+ return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.LessItemsExpected));
141
+ }
142
+ }
143
+ let i = 0;
144
+ for (const elem of what) {
145
+ const { error } = (0, exports.validateProperty)(elem, property.items, options);
146
+ if (error) {
147
+ if ('errors' in error) {
148
+ continue;
149
+ }
150
+ error.index = i;
151
+ return types_1.Result.error(error);
152
+ }
153
+ i++;
154
+ }
171
155
  }
172
156
  }
173
157
  }
174
158
  else if ('enum' in property) {
175
- if (!property.enum.includes(what)) {
159
+ if (!property.enum.includes(what) && property.enum.length === 0) {
176
160
  return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.ExtraneousElement, {
177
161
  expected: property.enum,
178
162
  got: what,
179
163
  }));
180
164
  }
181
165
  }
166
+ else if ('const' in property) {
167
+ if (what !== property.const) {
168
+ return types_1.Result.error(makePropertyError(types_2.PropertyValidationErrorCode.Unmatching, {
169
+ expected: property.const,
170
+ got: what,
171
+ }));
172
+ }
173
+ }
182
174
  return types_1.Result.result(what);
183
175
  };
184
176
  exports.validateProperty = validateProperty;
@@ -190,8 +182,7 @@ const validateWholeness = (what, schema) => {
190
182
  if (missingProps.length > 0) {
191
183
  return (0, exports.makeValidationError)({
192
184
  code: types_2.ValidationErrorCode.MissingProperties,
193
- errors: Object.fromEntries(missingProps
194
- .map((error) => [
185
+ errors: Object.fromEntries(missingProps.map((error) => [
195
186
  error,
196
187
  {
197
188
  type: 'missing',
@@ -202,47 +193,45 @@ const validateWholeness = (what, schema) => {
202
193
  };
203
194
  exports.validateWholeness = validateWholeness;
204
195
  const validate = (what, schema, options = {}) => {
205
- if (!what) {
196
+ if (what === undefined) {
206
197
  return types_1.Result.error((0, exports.makeValidationError)({
207
198
  code: types_2.ValidationErrorCode.EmptyTarget,
208
199
  errors: {},
209
200
  }));
210
201
  }
211
202
  if (!('properties' in schema)) {
212
- const { error } = (0, exports.validateProperty)('', what, schema);
213
- return error
214
- ? types_1.Result.error(error)
215
- : types_1.Result.result(what);
203
+ const { error } = (0, exports.validateProperty)(what, schema);
204
+ if (error) {
205
+ return types_1.Result.error(error);
206
+ }
207
+ return types_1.Result.result(what);
216
208
  }
217
209
  const wholenessError = (0, exports.validateWholeness)(what, schema);
218
210
  if (wholenessError) {
219
211
  if (options.throwOnError) {
220
- throw new Error(types_2.ValidationErrorCode.MissingProperties);
212
+ throw new TypeError(types_2.ValidationErrorCode.MissingProperties);
221
213
  }
222
214
  return types_1.Result.error(wholenessError);
223
215
  }
224
216
  const errors = {};
225
217
  const resultCopy = {};
226
218
  for (const propName in what) {
227
- const { error, result: parsed } = (0, exports.validateProperty)(propName, what[propName], schema.properties[propName], {
219
+ const { error, result: parsed } = (0, exports.validateProperty)(what[propName], schema.properties[propName], {
228
220
  ...options,
229
221
  parentProperty: schema,
230
222
  });
231
223
  if (error) {
224
+ if (options.throwOnError) {
225
+ throw new TypeError(types_2.ValidationErrorCode.InvalidProperties);
226
+ }
232
227
  errors[propName] = error;
228
+ continue;
233
229
  }
234
230
  if (parsed !== undefined) {
235
231
  resultCopy[propName] = parsed;
236
232
  }
237
233
  }
238
234
  if (Object.keys(errors).length > 0) {
239
- if (options.throwOnError) {
240
- const error = new TypeError(types_2.ValidationErrorCode.InvalidProperties);
241
- Object.assign(error, {
242
- errors,
243
- });
244
- throw error;
245
- }
246
235
  return types_1.Result.error((0, exports.makeValidationError)({
247
236
  code: types_2.ValidationErrorCode.InvalidProperties,
248
237
  errors,
package/dist/validate.mjs CHANGED
@@ -2,9 +2,6 @@
2
2
  import { Result } from "@aeriajs/types";
3
3
  import { getMissingProperties } from "@aeriajs/common";
4
4
  import { ValidationErrorCode, PropertyValidationErrorCode } from "@aeriajs/types";
5
- const getValueType = (value) => {
6
- return Array.isArray(value) ? "array" : typeof value;
7
- };
8
5
  const getPropertyType = (property) => {
9
6
  if ("type" in property) {
10
7
  if ("format" in property && property.format) {
@@ -22,7 +19,7 @@ const getPropertyType = (property) => {
22
19
  if ("const" in property) {
23
20
  return typeof property.const;
24
21
  }
25
- if ("$ref" in property || "properties" in property || "additionalProperties" in property) {
22
+ if ("properties" in property || "additionalProperties" in property || "$ref" in property) {
26
23
  return "object";
27
24
  }
28
25
  };
@@ -35,13 +32,13 @@ const makePropertyError = (type, details) => {
35
32
  export const makeValidationError = (error) => {
36
33
  return error;
37
34
  };
38
- export const validateProperty = (propName, what, property, options = {}) => {
35
+ export const validateProperty = (what, property, options = {}) => {
39
36
  if (!property) {
40
37
  if (options.parentProperty && "additionalProperties" in options.parentProperty && options.parentProperty.additionalProperties) {
41
- if (options.filterOutExtraneous) {
42
- return Result.result(void 0);
38
+ if (options.parentProperty.additionalProperties === true) {
39
+ return Result.result(what);
43
40
  }
44
- return Result.result(what);
41
+ return validateProperty(what, options.parentProperty.additionalProperties);
45
42
  }
46
43
  if (options.tolerateExtraneous) {
47
44
  return Result.result(void 0);
@@ -55,8 +52,8 @@ export const validateProperty = (propName, what, property, options = {}) => {
55
52
  return Result.result(void 0);
56
53
  }
57
54
  const expectedType = getPropertyType(property);
58
- const actualType = getValueType(what);
59
- if (actualType !== expectedType && !(("items" in property || "enum" in property) && actualType === "array") && !(actualType === "number" && expectedType === "integer")) {
55
+ const actualType = Array.isArray(what) ? "array" : typeof what;
56
+ if (actualType !== expectedType && !(actualType === "number" && expectedType === "integer")) {
60
57
  if (expectedType === "datetime" && what instanceof Date) {
61
58
  return Result.result(what);
62
59
  }
@@ -87,83 +84,79 @@ export const validateProperty = (propName, what, property, options = {}) => {
87
84
  got: actualType
88
85
  }));
89
86
  }
90
- if ("properties" in property) {
91
- return validate(what, property, options);
92
- }
93
- if ("enum" in property && property.enum.length === 0) {
94
- return Result.result(what);
95
- }
96
- if ("const" in property) {
97
- if (what !== property.const) {
98
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
99
- expected: property.const,
100
- got: what
101
- }));
102
- }
103
- return Result.result(what);
104
- }
105
- if ("items" in property) {
106
- if (!Array.isArray(what)) {
107
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
108
- expected: expectedType,
109
- got: actualType
110
- }));
111
- }
112
- if (property.minItems) {
113
- if (what.length < property.minItems) {
114
- return Result.error(makePropertyError(PropertyValidationErrorCode.MoreItemsExpected));
115
- }
116
- }
117
- if (property.maxItems) {
118
- if (what.length > property.maxItems) {
119
- return Result.error(makePropertyError(PropertyValidationErrorCode.LessItemsExpected));
120
- }
121
- }
122
- let i = 0;
123
- for (const elem of what) {
124
- const { error } = validateProperty(propName, elem, property.items, options);
125
- if (error) {
126
- if ("errors" in error) {
127
- continue;
128
- }
129
- error.index = i;
130
- return Result.error(error);
131
- }
132
- i++;
133
- }
134
- } else if ("type" in property) {
87
+ if ("type" in property) {
135
88
  switch (property.type) {
136
- case "number":
137
89
  case "integer": {
90
+ if (!Number.isInteger(what)) {
91
+ return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
92
+ expected: "integer",
93
+ got: "invalid_number"
94
+ }));
95
+ }
96
+ }
97
+ case "number": {
138
98
  if (typeof what !== "number") {
139
99
  return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
140
100
  expected: expectedType,
141
101
  got: actualType
142
102
  }));
143
103
  }
144
- if (property.type === "integer") {
145
- if (!Number.isInteger(what)) {
146
- return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
147
- expected: "integer",
148
- got: "invalid_number"
149
- }));
150
- }
151
- }
152
- if (property.maximum && property.maximum < what || property.minimum && property.minimum > what || property.exclusiveMaximum && property.exclusiveMaximum <= what || property.exclusiveMinimum && property.exclusiveMinimum >= what) {
104
+ if (typeof property.maximum === "number" && property.maximum < what || typeof property.minimum === "number" && property.minimum > what || typeof property.exclusiveMaximum === "number" && property.exclusiveMaximum <= what || typeof property.exclusiveMinimum === "number" && property.exclusiveMinimum >= what) {
153
105
  return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
154
106
  expected: "number",
155
107
  got: "invalid_number"
156
108
  }));
157
109
  }
110
+ break;
111
+ }
112
+ case "object": {
113
+ return validate(what, property, options);
114
+ }
115
+ case "array": {
116
+ if (!Array.isArray(what)) {
117
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
118
+ expected: expectedType,
119
+ got: actualType
120
+ }));
121
+ }
122
+ if (property.minItems) {
123
+ if (what.length < property.minItems) {
124
+ return Result.error(makePropertyError(PropertyValidationErrorCode.MoreItemsExpected));
125
+ }
126
+ }
127
+ if (property.maxItems) {
128
+ if (what.length > property.maxItems) {
129
+ return Result.error(makePropertyError(PropertyValidationErrorCode.LessItemsExpected));
130
+ }
131
+ }
132
+ let i = 0;
133
+ for (const elem of what) {
134
+ const { error } = validateProperty(elem, property.items, options);
135
+ if (error) {
136
+ if ("errors" in error) {
137
+ continue;
138
+ }
139
+ error.index = i;
140
+ return Result.error(error);
141
+ }
142
+ i++;
143
+ }
158
144
  }
159
145
  }
160
146
  } else if ("enum" in property) {
161
- if (!property.enum.includes(what)) {
147
+ if (!property.enum.includes(what) && property.enum.length === 0) {
162
148
  return Result.error(makePropertyError(PropertyValidationErrorCode.ExtraneousElement, {
163
149
  expected: property.enum,
164
150
  got: what
165
151
  }));
166
152
  }
153
+ } else if ("const" in property) {
154
+ if (what !== property.const) {
155
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
156
+ expected: property.const,
157
+ got: what
158
+ }));
159
+ }
167
160
  }
168
161
  return Result.result(what);
169
162
  };
@@ -183,50 +176,45 @@ export const validateWholeness = (what, schema) => {
183
176
  }
184
177
  };
185
178
  export const validate = (what, schema, options = {}) => {
186
- if (!what) {
179
+ if (what === void 0) {
187
180
  return Result.error(makeValidationError({
188
181
  code: ValidationErrorCode.EmptyTarget,
189
182
  errors: {}
190
183
  }));
191
184
  }
192
185
  if (!("properties" in schema)) {
193
- const { error } = validateProperty("", what, schema);
194
- return error ? Result.error(error) : Result.result(what);
186
+ const { error } = validateProperty(what, schema);
187
+ if (error) {
188
+ return Result.error(error);
189
+ }
190
+ return Result.result(what);
195
191
  }
196
192
  const wholenessError = validateWholeness(what, schema);
197
193
  if (wholenessError) {
198
194
  if (options.throwOnError) {
199
- throw new Error(ValidationErrorCode.MissingProperties);
195
+ throw new TypeError(ValidationErrorCode.MissingProperties);
200
196
  }
201
197
  return Result.error(wholenessError);
202
198
  }
203
199
  const errors = {};
204
200
  const resultCopy = {};
205
201
  for (const propName in what) {
206
- const { error, result: parsed } = validateProperty(
207
- propName,
208
- what[propName],
209
- schema.properties[propName],
210
- {
211
- ...options,
212
- parentProperty: schema
213
- }
214
- );
202
+ const { error, result: parsed } = validateProperty(what[propName], schema.properties[propName], {
203
+ ...options,
204
+ parentProperty: schema
205
+ });
215
206
  if (error) {
207
+ if (options.throwOnError) {
208
+ throw new TypeError(ValidationErrorCode.InvalidProperties);
209
+ }
216
210
  errors[propName] = error;
211
+ continue;
217
212
  }
218
213
  if (parsed !== void 0) {
219
214
  resultCopy[propName] = parsed;
220
215
  }
221
216
  }
222
217
  if (Object.keys(errors).length > 0) {
223
- if (options.throwOnError) {
224
- const error = new TypeError(ValidationErrorCode.InvalidProperties);
225
- Object.assign(error, {
226
- errors
227
- });
228
- throw error;
229
- }
230
218
  return Result.error(makeValidationError({
231
219
  code: ValidationErrorCode.InvalidProperties,
232
220
  errors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/validation",
3
- "version": "0.0.125",
3
+ "version": "0.0.127",
4
4
  "description": "## Installation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",