@aeriajs/validation 0.0.177 → 0.0.179

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/dist/index.js CHANGED
@@ -1,17 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./validate.js"), exports);
1
+ export * from './validate.js';
package/dist/validate.js CHANGED
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validator = exports.validatePropertyWithRefs = exports.validateWithRefs = exports.validate = exports.validateWholeness = exports.validateRefs = exports.validateProperty = exports.makeValidationError = void 0;
4
- const common_1 = require("@aeriajs/common");
5
- const types_1 = require("@aeriajs/types");
6
- const entrypoint_1 = require("@aeriajs/entrypoint");
1
+ import { convertConditionToQuery, getMissingProperties } from '@aeriajs/common';
2
+ import { Result, ValidationErrorCode, PropertyValidationErrorCode } from '@aeriajs/types';
3
+ import { getCollection } from '@aeriajs/entrypoint';
7
4
  const isValidObjectId = (what) => {
8
5
  return /^[0-9a-f]{24}$/.test(what);
9
6
  };
@@ -38,28 +35,27 @@ const makePropertyError = (type, details) => {
38
35
  details,
39
36
  };
40
37
  };
41
- const makeValidationError = (error) => {
38
+ export const makeValidationError = (error) => {
42
39
  return error;
43
40
  };
44
- exports.makeValidationError = makeValidationError;
45
- const validateProperty = (what, property, options = {}) => {
41
+ export const validateProperty = (what, property, options = {}) => {
46
42
  if (!property) {
47
43
  if (options.parentProperty && 'additionalProperties' in options.parentProperty) {
48
44
  if (options.parentProperty.additionalProperties === true) {
49
- return types_1.Result.result(what);
45
+ return Result.result(what);
50
46
  }
51
- return (0, exports.validateProperty)(what, options.parentProperty.additionalProperties);
47
+ return validateProperty(what, options.parentProperty.additionalProperties);
52
48
  }
53
49
  if (options.tolerateExtraneous) {
54
- return types_1.Result.result(undefined);
50
+ return Result.result(undefined);
55
51
  }
56
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Extraneous));
52
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Extraneous));
57
53
  }
58
54
  if (what === null || what === undefined) {
59
- return types_1.Result.result(what);
55
+ return Result.result(what);
60
56
  }
61
57
  if ('getter' in property) {
62
- return types_1.Result.result(undefined);
58
+ return Result.result(undefined);
63
59
  }
64
60
  const expectedType = getPropertyType(property);
65
61
  const actualType = Array.isArray(what)
@@ -68,15 +64,15 @@ const validateProperty = (what, property, options = {}) => {
68
64
  if (actualType !== expectedType
69
65
  && !(actualType === 'number' && expectedType === 'integer')) {
70
66
  if (expectedType === 'datetime' && what instanceof Date) {
71
- return types_1.Result.result(what);
67
+ return Result.result(what);
72
68
  }
73
69
  if ('$ref' in property) {
74
70
  switch (typeof what) {
75
71
  case 'string': {
76
72
  if (isValidObjectId(what)) {
77
- return types_1.Result.result(what);
73
+ return Result.result(what);
78
74
  }
79
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
75
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
80
76
  expected: expectedType,
81
77
  got: actualType,
82
78
  }));
@@ -87,28 +83,28 @@ const validateProperty = (what, property, options = {}) => {
87
83
  if (expectedType === 'number' && typeof what === 'string') {
88
84
  const coerced = parseFloat(what);
89
85
  if (!isNaN(coerced)) {
90
- return types_1.Result.result(coerced);
86
+ return Result.result(coerced);
91
87
  }
92
88
  }
93
89
  if (expectedType === 'integer' && typeof what === 'string') {
94
90
  const coerced = parseInt(what);
95
91
  if (!isNaN(coerced)) {
96
- return types_1.Result.result(coerced);
92
+ return Result.result(coerced);
97
93
  }
98
94
  }
99
95
  if (expectedType === 'string' && typeof what === 'number') {
100
- return types_1.Result.result(String(what));
96
+ return Result.result(String(what));
101
97
  }
102
98
  if (expectedType === 'datetime' && typeof what === 'string') {
103
- return types_1.Result.result(new Date(what));
99
+ return Result.result(new Date(what));
104
100
  }
105
101
  }
106
102
  if ((options.coerce || options.coerceObjectIds) && options.objectIdConstructor) {
107
103
  if (('$ref' in property || 'format' in property && property.format === 'objectid') && typeof what === 'string') {
108
- return types_1.Result.result(new options.objectIdConstructor(what));
104
+ return Result.result(new options.objectIdConstructor(what));
109
105
  }
110
106
  }
111
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
107
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
112
108
  expected: expectedType,
113
109
  got: actualType,
114
110
  }));
@@ -116,25 +112,40 @@ const validateProperty = (what, property, options = {}) => {
116
112
  if ('type' in property) {
117
113
  switch (property.type) {
118
114
  case 'string': {
119
- if (typeof what !== 'string') {
120
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
121
- expected: expectedType,
122
- got: actualType,
123
- }));
124
- }
125
- if ((property.format === 'objectid' && !isValidObjectId(what))
126
- || (typeof property.minLength === 'number' && property.minLength > what.length)
127
- || (typeof property.maxLength === 'number' && property.maxLength < what.length)) {
128
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.StringConstraint, {
129
- expected: 'string',
130
- got: 'invalid_string',
131
- }));
115
+ switch (property.format) {
116
+ case 'objectid': {
117
+ if (!options.objectIdConstructor) {
118
+ throw new Error;
119
+ }
120
+ if (!(what instanceof options.objectIdConstructor)) {
121
+ return Result.error(makePropertyError(PropertyValidationErrorCode.StringConstraint, {
122
+ expected: 'objectid',
123
+ got: 'invalid_objectid',
124
+ }));
125
+ }
126
+ break;
127
+ }
128
+ default: {
129
+ if (typeof what !== 'string') {
130
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
131
+ expected: expectedType,
132
+ got: actualType,
133
+ }));
134
+ }
135
+ if ((typeof property.minLength === 'number' && property.minLength > what.length)
136
+ || (typeof property.maxLength === 'number' && property.maxLength < what.length)) {
137
+ return Result.error(makePropertyError(PropertyValidationErrorCode.StringConstraint, {
138
+ expected: 'string',
139
+ got: 'invalid_string',
140
+ }));
141
+ }
142
+ }
132
143
  }
133
144
  break;
134
145
  }
135
146
  case 'integer': {
136
147
  if (!Number.isInteger(what)) {
137
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.NumericConstraint, {
148
+ return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
138
149
  expected: 'integer',
139
150
  got: 'invalid_number',
140
151
  }));
@@ -142,7 +153,7 @@ const validateProperty = (what, property, options = {}) => {
142
153
  }
143
154
  case 'number': {
144
155
  if (typeof what !== 'number') {
145
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
156
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
146
157
  expected: expectedType,
147
158
  got: actualType,
148
159
  }));
@@ -151,7 +162,7 @@ const validateProperty = (what, property, options = {}) => {
151
162
  || (typeof property.minimum === 'number' && property.minimum > what)
152
163
  || (typeof property.exclusiveMaximum === 'number' && property.exclusiveMaximum <= what)
153
164
  || (typeof property.exclusiveMinimum === 'number' && property.exclusiveMinimum >= what)) {
154
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.NumericConstraint, {
165
+ return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
155
166
  expected: 'number',
156
167
  got: 'invalid_number',
157
168
  }));
@@ -160,39 +171,39 @@ const validateProperty = (what, property, options = {}) => {
160
171
  }
161
172
  case 'object': {
162
173
  if ('properties' in property) {
163
- return (0, exports.validate)(what, property, options);
174
+ return validate(what, property, options);
164
175
  }
165
176
  switch (typeof property.additionalProperties) {
166
- case 'object': return (0, exports.validate)(what, property.additionalProperties, options);
167
- case 'boolean': return types_1.Result.result(what);
177
+ case 'object': return validate(what, property.additionalProperties, options);
178
+ case 'boolean': return Result.result(what);
168
179
  }
169
180
  }
170
181
  case 'array': {
171
182
  if (!Array.isArray(what)) {
172
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
183
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
173
184
  expected: expectedType,
174
185
  got: actualType,
175
186
  }));
176
187
  }
177
188
  if (property.minItems) {
178
189
  if (what.length < property.minItems) {
179
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.MoreItemsExpected));
190
+ return Result.error(makePropertyError(PropertyValidationErrorCode.MoreItemsExpected));
180
191
  }
181
192
  }
182
193
  if (property.maxItems) {
183
194
  if (what.length > property.maxItems) {
184
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.LessItemsExpected));
195
+ return Result.error(makePropertyError(PropertyValidationErrorCode.LessItemsExpected));
185
196
  }
186
197
  }
187
198
  let i = 0;
188
199
  for (const elem of what) {
189
- const { error } = (0, exports.validateProperty)(elem, property.items, options);
200
+ const { error } = validateProperty(elem, property.items, options);
190
201
  if (error) {
191
202
  if ('code' in error) {
192
203
  continue;
193
204
  }
194
205
  error.index = i;
195
- return types_1.Result.error(error);
206
+ return Result.error(error);
196
207
  }
197
208
  i++;
198
209
  }
@@ -201,7 +212,7 @@ const validateProperty = (what, property, options = {}) => {
201
212
  }
202
213
  else if ('enum' in property) {
203
214
  if (!property.enum.includes(what)) {
204
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.ExtraneousElement, {
215
+ return Result.error(makePropertyError(PropertyValidationErrorCode.ExtraneousElement, {
205
216
  expected: property.enum,
206
217
  got: what,
207
218
  }));
@@ -209,26 +220,25 @@ const validateProperty = (what, property, options = {}) => {
209
220
  }
210
221
  else if ('const' in property) {
211
222
  if (what !== property.const) {
212
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
223
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
213
224
  expected: property.const,
214
225
  got: what,
215
226
  }));
216
227
  }
217
228
  }
218
- return types_1.Result.result(what);
229
+ return Result.result(what);
219
230
  };
220
- exports.validateProperty = validateProperty;
221
- const validateRefs = async (what, property, options = {}) => {
231
+ export const validateRefs = async (what, property, options = {}) => {
222
232
  if ('$ref' in property) {
223
233
  if (options.checkObjectIds) {
224
234
  if (!options.context || !options.objectIdConstructor) {
225
235
  throw new Error;
226
236
  }
227
237
  if (what === null) {
228
- return types_1.Result.result({});
238
+ return Result.result({});
229
239
  }
230
240
  if (!isValidObjectId(String(what))) {
231
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
241
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
232
242
  expected: 'objectid',
233
243
  got: typeof what,
234
244
  }));
@@ -240,7 +250,7 @@ const validateRefs = async (what, property, options = {}) => {
240
250
  {
241
251
  _id: new options.objectIdConstructor(what),
242
252
  },
243
- (0, common_1.convertConditionToQuery)(property.constraints),
253
+ convertConditionToQuery(property.constraints),
244
254
  ],
245
255
  };
246
256
  }
@@ -255,69 +265,71 @@ const validateRefs = async (what, property, options = {}) => {
255
265
  },
256
266
  });
257
267
  if (!exists) {
258
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.ReferenceConstraint, {
268
+ return Result.error(makePropertyError(PropertyValidationErrorCode.ReferenceConstraint, {
259
269
  expected: 'objectid',
260
270
  got: 'invalid_objectid',
261
271
  }));
262
272
  }
263
- return types_1.Result.result({});
273
+ return Result.result({});
264
274
  }
265
275
  let description;
266
276
  if (options.descriptions) {
267
277
  description = options.descriptions[property.$ref];
268
278
  }
269
279
  else {
270
- const collection = await (0, entrypoint_1.getCollection)(property.$ref);
280
+ const collection = await getCollection(property.$ref);
271
281
  if (!collection) {
272
282
  throw new Error;
273
283
  }
274
284
  description = collection.description;
275
285
  }
276
286
  if (typeof what !== 'object') {
277
- return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
287
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
278
288
  expected: 'object',
279
289
  got: typeof what,
280
290
  }));
281
291
  }
282
- return (0, exports.validate)(what, description, options);
292
+ return validate(what, description, options);
283
293
  }
284
294
  else if ('items' in property) {
285
295
  if (!Array.isArray(what)) {
286
296
  throw new Error;
287
297
  }
288
298
  for (const elem of what) {
289
- const { error } = await (0, exports.validateRefs)(elem, property.items, options);
299
+ const { error } = await validateRefs(elem, property.items, options);
290
300
  if (error) {
291
- return types_1.Result.error(error);
301
+ return Result.error(error);
292
302
  }
293
303
  }
294
304
  }
295
305
  else if ('properties' in property) {
296
306
  const details = {};
297
307
  for (const propName in what) {
298
- const { error } = await (0, exports.validateRefs)(what[propName], property.properties[propName], options);
308
+ if (!(propName in property.properties)) {
309
+ continue;
310
+ }
311
+ const { error } = await validateRefs(what[propName], property.properties[propName], options);
299
312
  if (error) {
300
313
  details[propName] = error;
301
314
  }
302
315
  }
303
316
  if (Object.keys(details).length > 0) {
304
- return types_1.Result.error((0, exports.makeValidationError)({
305
- code: types_1.ValidationErrorCode.InvalidProperties,
317
+ return Result.error(makeValidationError({
318
+ code: ValidationErrorCode.InvalidProperties,
306
319
  details,
307
320
  }));
308
321
  }
309
322
  }
310
- return types_1.Result.result({});
323
+ return Result.result({});
311
324
  };
312
- exports.validateRefs = validateRefs;
313
- const validateWholeness = (what, schema) => {
325
+ export const validateWholeness = (what, schema) => {
314
326
  const required = schema.required
315
327
  ? schema.required
316
328
  : Object.keys(schema.properties);
317
- const missingProps = (0, common_1.getMissingProperties)(what, schema, required);
329
+ const missingProps = getMissingProperties(what, schema, required);
318
330
  if (missingProps.length > 0) {
319
- return (0, exports.makeValidationError)({
320
- code: types_1.ValidationErrorCode.MissingProperties,
331
+ return makeValidationError({
332
+ code: ValidationErrorCode.MissingProperties,
321
333
  details: Object.fromEntries(missingProps.map((error) => [
322
334
  error,
323
335
  {
@@ -327,38 +339,37 @@ const validateWholeness = (what, schema) => {
327
339
  });
328
340
  }
329
341
  };
330
- exports.validateWholeness = validateWholeness;
331
- const validate = (what, schema, options = {}) => {
342
+ export const validate = (what, schema, options = {}) => {
332
343
  if (what === undefined) {
333
- return types_1.Result.error((0, exports.makeValidationError)({
334
- code: types_1.ValidationErrorCode.EmptyTarget,
344
+ return Result.error(makeValidationError({
345
+ code: ValidationErrorCode.EmptyTarget,
335
346
  details: {},
336
347
  }));
337
348
  }
338
349
  if (!('properties' in schema)) {
339
- const { error } = (0, exports.validateProperty)(what, schema);
350
+ const { error } = validateProperty(what, schema);
340
351
  if (error) {
341
- return types_1.Result.error(error);
352
+ return Result.error(error);
342
353
  }
343
- return types_1.Result.result(what);
354
+ return Result.result(what);
344
355
  }
345
- const wholenessError = (0, exports.validateWholeness)(what, schema);
356
+ const wholenessError = validateWholeness(what, schema);
346
357
  if (wholenessError) {
347
358
  if (options.throwOnError) {
348
- throw new TypeError(types_1.ValidationErrorCode.MissingProperties);
359
+ throw new TypeError(ValidationErrorCode.MissingProperties);
349
360
  }
350
- return types_1.Result.error(wholenessError);
361
+ return Result.error(wholenessError);
351
362
  }
352
363
  const details = {};
353
364
  const resultCopy = {};
354
365
  for (const propName in what) {
355
- const { error, result: parsed } = (0, exports.validateProperty)(what[propName], schema.properties[propName], {
366
+ const { error, result: parsed } = validateProperty(what[propName], schema.properties[propName], {
356
367
  ...options,
357
368
  parentProperty: schema,
358
369
  });
359
370
  if (error) {
360
371
  if (options.throwOnError) {
361
- throw new TypeError(types_1.ValidationErrorCode.InvalidProperties);
372
+ throw new TypeError(ValidationErrorCode.InvalidProperties);
362
373
  }
363
374
  details[propName] = error;
364
375
  continue;
@@ -368,36 +379,32 @@ const validate = (what, schema, options = {}) => {
368
379
  }
369
380
  }
370
381
  if (Object.keys(details).length > 0) {
371
- return types_1.Result.error((0, exports.makeValidationError)({
372
- code: types_1.ValidationErrorCode.InvalidProperties,
382
+ return Result.error(makeValidationError({
383
+ code: ValidationErrorCode.InvalidProperties,
373
384
  details,
374
385
  }));
375
386
  }
376
- return types_1.Result.result(resultCopy);
387
+ return Result.result(resultCopy);
377
388
  };
378
- exports.validate = validate;
379
- const validateWithRefs = async (what, schema, options = {}) => {
380
- const { error: refsError } = await (0, exports.validateRefs)(what, schema, options);
389
+ export const validateWithRefs = async (what, schema, options = {}) => {
390
+ const { error: refsError } = await validateRefs(what, schema, options);
381
391
  if (refsError) {
382
- return types_1.Result.error(refsError);
392
+ return Result.error(refsError);
383
393
  }
384
- return (0, exports.validate)(what, schema, options);
394
+ return validate(what, schema, options);
385
395
  };
386
- exports.validateWithRefs = validateWithRefs;
387
- const validatePropertyWithRefs = async (what, property, options = {}) => {
388
- const { error: refsError } = await (0, exports.validateRefs)(what, property, options);
396
+ export const validatePropertyWithRefs = async (what, property, options = {}) => {
397
+ const { error: refsError } = await validateRefs(what, property, options);
389
398
  if (refsError) {
390
- return types_1.Result.error(refsError);
399
+ return Result.error(refsError);
391
400
  }
392
- return (0, exports.validateProperty)(what, property, options);
401
+ return validateProperty(what, property, options);
393
402
  };
394
- exports.validatePropertyWithRefs = validatePropertyWithRefs;
395
- const validator = (schema, options = {}) => {
403
+ export const validator = (schema, options = {}) => {
396
404
  return [
397
405
  {},
398
406
  (what) => {
399
- return (0, exports.validate)(what, schema, options);
407
+ return validate(what, schema, options);
400
408
  },
401
409
  ];
402
410
  };
403
- exports.validator = validator;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@aeriajs/validation",
3
- "version": "0.0.177",
3
+ "type": "module",
4
+ "version": "0.0.179",
4
5
  "description": "## Installation",
5
6
  "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "publishConfig": {
9
9
  "access": "public"
@@ -17,8 +17,7 @@
17
17
  "exports": {
18
18
  ".": {
19
19
  "types": "./dist/index.d.ts",
20
- "import": "./dist/index.mjs",
21
- "require": "./dist/index.js"
20
+ "default": "./dist/index.js"
22
21
  }
23
22
  },
24
23
  "devDependencies": {
@@ -28,9 +27,9 @@
28
27
  "mongodb": "^6.17.0"
29
28
  },
30
29
  "peerDependencies": {
31
- "@aeriajs/common": "^0.0.157",
32
- "@aeriajs/entrypoint": "^0.0.163",
33
- "@aeriajs/types": "^0.0.135",
30
+ "@aeriajs/common": "^0.0.158",
31
+ "@aeriajs/entrypoint": "^0.0.164",
32
+ "@aeriajs/types": "^0.0.136",
34
33
  "mongodb": "^6.17.0"
35
34
  },
36
35
  "scripts": {
@@ -38,9 +37,6 @@
38
37
  "test:typecheck": "tsc -p tsconfig.test.json",
39
38
  "lint": "eslint .",
40
39
  "lint:fix": "eslint . --fix",
41
- "build": "pnpm build:cjs && pnpm build:esm",
42
- "build:cjs": "tsc",
43
- "build:esm": "esbuild './src/**/*.ts' --outdir=dist --out-extension:.js=.mjs && pnpm build:esm-transform",
44
- "build:esm-transform": "pnpm -w esm-transform $PWD/dist"
40
+ "build": "tsc"
45
41
  }
46
42
  }
package/dist/index.mjs DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- export * from "./validate.mjs";
package/dist/validate.mjs DELETED
@@ -1,377 +0,0 @@
1
- "use strict";
2
- import { convertConditionToQuery, getMissingProperties } from "@aeriajs/common";
3
- import { Result, ValidationErrorCode, PropertyValidationErrorCode } from "@aeriajs/types";
4
- import { getCollection } from "@aeriajs/entrypoint";
5
- const isValidObjectId = (what) => {
6
- return /^[0-9a-f]{24}$/.test(what);
7
- };
8
- const getPropertyType = (property) => {
9
- if ("type" in property) {
10
- if ("format" in property && property.format) {
11
- switch (property.format) {
12
- case "date":
13
- case "date-time":
14
- return "datetime";
15
- case "objectid":
16
- return "object";
17
- }
18
- }
19
- return property.type;
20
- }
21
- if ("enum" in property) {
22
- return typeof property.enum[0];
23
- }
24
- if ("const" in property) {
25
- return typeof property.const;
26
- }
27
- if ("properties" in property || "additionalProperties" in property || "$ref" in property) {
28
- return "object";
29
- }
30
- };
31
- const makePropertyError = (type, details) => {
32
- return {
33
- type,
34
- details
35
- };
36
- };
37
- export const makeValidationError = (error) => {
38
- return error;
39
- };
40
- export const validateProperty = (what, property, options = {}) => {
41
- if (!property) {
42
- if (options.parentProperty && "additionalProperties" in options.parentProperty) {
43
- if (options.parentProperty.additionalProperties === true) {
44
- return Result.result(what);
45
- }
46
- return validateProperty(what, options.parentProperty.additionalProperties);
47
- }
48
- if (options.tolerateExtraneous) {
49
- return Result.result(void 0);
50
- }
51
- return Result.error(makePropertyError(PropertyValidationErrorCode.Extraneous));
52
- }
53
- if (what === null || what === void 0) {
54
- return Result.result(what);
55
- }
56
- if ("getter" in property) {
57
- return Result.result(void 0);
58
- }
59
- const expectedType = getPropertyType(property);
60
- const actualType = Array.isArray(what) ? "array" : typeof what;
61
- if (actualType !== expectedType && !(actualType === "number" && expectedType === "integer")) {
62
- if (expectedType === "datetime" && what instanceof Date) {
63
- return Result.result(what);
64
- }
65
- if ("$ref" in property) {
66
- switch (typeof what) {
67
- case "string": {
68
- if (isValidObjectId(what)) {
69
- return Result.result(what);
70
- }
71
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
72
- expected: expectedType,
73
- got: actualType
74
- }));
75
- }
76
- }
77
- }
78
- if (options.coerce) {
79
- if (expectedType === "number" && typeof what === "string") {
80
- const coerced = parseFloat(what);
81
- if (!isNaN(coerced)) {
82
- return Result.result(coerced);
83
- }
84
- }
85
- if (expectedType === "integer" && typeof what === "string") {
86
- const coerced = parseInt(what);
87
- if (!isNaN(coerced)) {
88
- return Result.result(coerced);
89
- }
90
- }
91
- if (expectedType === "string" && typeof what === "number") {
92
- return Result.result(String(what));
93
- }
94
- if (expectedType === "datetime" && typeof what === "string") {
95
- return Result.result(new Date(what));
96
- }
97
- }
98
- if ((options.coerce || options.coerceObjectIds) && options.objectIdConstructor) {
99
- if (("$ref" in property || "format" in property && property.format === "objectid") && typeof what === "string") {
100
- return Result.result(new options.objectIdConstructor(what));
101
- }
102
- }
103
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
104
- expected: expectedType,
105
- got: actualType
106
- }));
107
- }
108
- if ("type" in property) {
109
- switch (property.type) {
110
- case "string": {
111
- if (typeof what !== "string") {
112
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
113
- expected: expectedType,
114
- got: actualType
115
- }));
116
- }
117
- if (property.format === "objectid" && !isValidObjectId(what) || typeof property.minLength === "number" && property.minLength > what.length || typeof property.maxLength === "number" && property.maxLength < what.length) {
118
- return Result.error(makePropertyError(PropertyValidationErrorCode.StringConstraint, {
119
- expected: "string",
120
- got: "invalid_string"
121
- }));
122
- }
123
- break;
124
- }
125
- case "integer": {
126
- if (!Number.isInteger(what)) {
127
- return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
128
- expected: "integer",
129
- got: "invalid_number"
130
- }));
131
- }
132
- }
133
- case "number": {
134
- if (typeof what !== "number") {
135
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
136
- expected: expectedType,
137
- got: actualType
138
- }));
139
- }
140
- 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) {
141
- return Result.error(makePropertyError(PropertyValidationErrorCode.NumericConstraint, {
142
- expected: "number",
143
- got: "invalid_number"
144
- }));
145
- }
146
- break;
147
- }
148
- case "object": {
149
- if ("properties" in property) {
150
- return validate(what, property, options);
151
- }
152
- switch (typeof property.additionalProperties) {
153
- case "object":
154
- return validate(what, property.additionalProperties, options);
155
- case "boolean":
156
- return Result.result(what);
157
- }
158
- }
159
- case "array": {
160
- if (!Array.isArray(what)) {
161
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
162
- expected: expectedType,
163
- got: actualType
164
- }));
165
- }
166
- if (property.minItems) {
167
- if (what.length < property.minItems) {
168
- return Result.error(makePropertyError(PropertyValidationErrorCode.MoreItemsExpected));
169
- }
170
- }
171
- if (property.maxItems) {
172
- if (what.length > property.maxItems) {
173
- return Result.error(makePropertyError(PropertyValidationErrorCode.LessItemsExpected));
174
- }
175
- }
176
- let i = 0;
177
- for (const elem of what) {
178
- const { error } = validateProperty(elem, property.items, options);
179
- if (error) {
180
- if ("code" in error) {
181
- continue;
182
- }
183
- error.index = i;
184
- return Result.error(error);
185
- }
186
- i++;
187
- }
188
- }
189
- }
190
- } else if ("enum" in property) {
191
- if (!property.enum.includes(what)) {
192
- return Result.error(makePropertyError(PropertyValidationErrorCode.ExtraneousElement, {
193
- expected: property.enum,
194
- got: what
195
- }));
196
- }
197
- } else if ("const" in property) {
198
- if (what !== property.const) {
199
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
200
- expected: property.const,
201
- got: what
202
- }));
203
- }
204
- }
205
- return Result.result(what);
206
- };
207
- export const validateRefs = async (what, property, options = {}) => {
208
- if ("$ref" in property) {
209
- if (options.checkObjectIds) {
210
- if (!options.context || !options.objectIdConstructor) {
211
- throw new Error();
212
- }
213
- if (what === null) {
214
- return Result.result({});
215
- }
216
- if (!isValidObjectId(String(what))) {
217
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
218
- expected: "objectid",
219
- got: typeof what
220
- }));
221
- }
222
- let query;
223
- if (property.constraints) {
224
- query = {
225
- $and: [
226
- {
227
- _id: new options.objectIdConstructor(what)
228
- },
229
- convertConditionToQuery(property.constraints)
230
- ]
231
- };
232
- } else {
233
- query = {
234
- _id: new options.objectIdConstructor(what)
235
- };
236
- }
237
- const exists = await options.context.collections[property.$ref].model.findOne(query, {
238
- projection: {
239
- _id: 1
240
- }
241
- });
242
- if (!exists) {
243
- return Result.error(makePropertyError(PropertyValidationErrorCode.ReferenceConstraint, {
244
- expected: "objectid",
245
- got: "invalid_objectid"
246
- }));
247
- }
248
- return Result.result({});
249
- }
250
- let description;
251
- if (options.descriptions) {
252
- description = options.descriptions[property.$ref];
253
- } else {
254
- const collection = await getCollection(property.$ref);
255
- if (!collection) {
256
- throw new Error();
257
- }
258
- description = collection.description;
259
- }
260
- if (typeof what !== "object") {
261
- return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
262
- expected: "object",
263
- got: typeof what
264
- }));
265
- }
266
- return validate(what, description, options);
267
- } else if ("items" in property) {
268
- if (!Array.isArray(what)) {
269
- throw new Error();
270
- }
271
- for (const elem of what) {
272
- const { error } = await validateRefs(elem, property.items, options);
273
- if (error) {
274
- return Result.error(error);
275
- }
276
- }
277
- } else if ("properties" in property) {
278
- const details = {};
279
- for (const propName in what) {
280
- const { error } = await validateRefs(what[propName], property.properties[propName], options);
281
- if (error) {
282
- details[propName] = error;
283
- }
284
- }
285
- if (Object.keys(details).length > 0) {
286
- return Result.error(makeValidationError({
287
- code: ValidationErrorCode.InvalidProperties,
288
- details
289
- }));
290
- }
291
- }
292
- return Result.result({});
293
- };
294
- export const validateWholeness = (what, schema) => {
295
- const required = schema.required ? schema.required : Object.keys(schema.properties);
296
- const missingProps = getMissingProperties(what, schema, required);
297
- if (missingProps.length > 0) {
298
- return makeValidationError({
299
- code: ValidationErrorCode.MissingProperties,
300
- details: Object.fromEntries(missingProps.map((error) => [
301
- error,
302
- {
303
- type: "missing"
304
- }
305
- ]))
306
- });
307
- }
308
- };
309
- export const validate = (what, schema, options = {}) => {
310
- if (what === void 0) {
311
- return Result.error(makeValidationError({
312
- code: ValidationErrorCode.EmptyTarget,
313
- details: {}
314
- }));
315
- }
316
- if (!("properties" in schema)) {
317
- const { error } = validateProperty(what, schema);
318
- if (error) {
319
- return Result.error(error);
320
- }
321
- return Result.result(what);
322
- }
323
- const wholenessError = validateWholeness(what, schema);
324
- if (wholenessError) {
325
- if (options.throwOnError) {
326
- throw new TypeError(ValidationErrorCode.MissingProperties);
327
- }
328
- return Result.error(wholenessError);
329
- }
330
- const details = {};
331
- const resultCopy = {};
332
- for (const propName in what) {
333
- const { error, result: parsed } = validateProperty(what[propName], schema.properties[propName], {
334
- ...options,
335
- parentProperty: schema
336
- });
337
- if (error) {
338
- if (options.throwOnError) {
339
- throw new TypeError(ValidationErrorCode.InvalidProperties);
340
- }
341
- details[propName] = error;
342
- continue;
343
- }
344
- if (parsed !== void 0) {
345
- resultCopy[propName] = parsed;
346
- }
347
- }
348
- if (Object.keys(details).length > 0) {
349
- return Result.error(makeValidationError({
350
- code: ValidationErrorCode.InvalidProperties,
351
- details
352
- }));
353
- }
354
- return Result.result(resultCopy);
355
- };
356
- export const validateWithRefs = async (what, schema, options = {}) => {
357
- const { error: refsError } = await validateRefs(what, schema, options);
358
- if (refsError) {
359
- return Result.error(refsError);
360
- }
361
- return validate(what, schema, options);
362
- };
363
- export const validatePropertyWithRefs = async (what, property, options = {}) => {
364
- const { error: refsError } = await validateRefs(what, property, options);
365
- if (refsError) {
366
- return Result.error(refsError);
367
- }
368
- return validateProperty(what, property, options);
369
- };
370
- export const validator = (schema, options = {}) => {
371
- return [
372
- {},
373
- (what) => {
374
- return validate(what, schema, options);
375
- }
376
- ];
377
- };