valgen 3.2.0 → 4.0.0-alpha.2

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.
Files changed (140) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +12 -7
  3. package/cjs/core/constants.js +5 -0
  4. package/cjs/core/context.js +65 -0
  5. package/cjs/core/index.js +21 -0
  6. package/cjs/core/types.js +2 -0
  7. package/cjs/core/validation-error.js +11 -0
  8. package/cjs/core/validator.js +61 -0
  9. package/cjs/helpers/object.utils.js +19 -0
  10. package/cjs/helpers/string.utils.js +9 -0
  11. package/cjs/index.js +18 -0
  12. package/cjs/package.json +3 -0
  13. package/cjs/rules/index.js +38 -0
  14. package/cjs/rules/is-any.js +12 -0
  15. package/cjs/rules/is-array.js +38 -0
  16. package/cjs/rules/is-boolean.js +30 -0
  17. package/cjs/rules/is-date.js +63 -0
  18. package/cjs/rules/is-empty.js +68 -0
  19. package/cjs/rules/is-enum.js +30 -0
  20. package/cjs/rules/is-integer.js +26 -0
  21. package/cjs/rules/is-matches.js +24 -0
  22. package/cjs/rules/is-null.js +40 -0
  23. package/cjs/rules/is-number.js +26 -0
  24. package/cjs/rules/is-object-id.js +28 -0
  25. package/cjs/rules/is-object.js +103 -0
  26. package/cjs/rules/is-record.js +41 -0
  27. package/cjs/rules/is-string.js +79 -0
  28. package/cjs/rules/is-tuple.js +32 -0
  29. package/cjs/rules/length.js +41 -0
  30. package/cjs/rules/optional.js +44 -0
  31. package/cjs/rules/pipe.js +43 -0
  32. package/cjs/rules/range.js +89 -0
  33. package/cjs/rules/string-formats.js +296 -0
  34. package/cjs/rules/union.js +31 -0
  35. package/cjs/rules/utilities.js +31 -0
  36. package/esm/core/constants.js +2 -0
  37. package/esm/core/context.js +61 -0
  38. package/esm/core/index.js +5 -0
  39. package/esm/core/types.js +1 -0
  40. package/esm/core/validation-error.js +7 -0
  41. package/esm/core/validator.js +56 -0
  42. package/esm/helpers/object.utils.js +14 -0
  43. package/esm/helpers/string.utils.js +5 -0
  44. package/esm/index.js +2 -0
  45. package/esm/rules/index.js +22 -0
  46. package/esm/rules/is-any.js +8 -0
  47. package/esm/rules/is-array.js +34 -0
  48. package/esm/rules/is-boolean.js +26 -0
  49. package/esm/rules/is-date.js +55 -0
  50. package/esm/rules/is-empty.js +63 -0
  51. package/esm/rules/is-enum.js +26 -0
  52. package/esm/rules/is-integer.js +22 -0
  53. package/esm/rules/is-matches.js +20 -0
  54. package/esm/rules/is-null.js +34 -0
  55. package/esm/rules/is-number.js +22 -0
  56. package/esm/rules/is-object-id.js +21 -0
  57. package/esm/rules/is-object.js +99 -0
  58. package/esm/rules/is-record.js +37 -0
  59. package/esm/rules/is-string.js +70 -0
  60. package/esm/rules/is-tuple.js +28 -0
  61. package/esm/rules/length.js +35 -0
  62. package/esm/rules/optional.js +38 -0
  63. package/esm/rules/pipe.js +38 -0
  64. package/esm/rules/range.js +81 -0
  65. package/esm/rules/string-formats.js +266 -0
  66. package/esm/rules/union.js +27 -0
  67. package/esm/rules/utilities.js +26 -0
  68. package/package.json +33 -37
  69. package/typings/core/constants.d.ts +2 -0
  70. package/typings/core/context.d.ts +26 -0
  71. package/typings/core/index.d.ts +6 -0
  72. package/typings/core/types.d.ts +18 -0
  73. package/typings/core/validation-error.d.ts +5 -0
  74. package/typings/core/validator.d.ts +18 -0
  75. package/typings/helpers/object.utils.d.ts +2 -0
  76. package/typings/helpers/string.utils.d.ts +1 -0
  77. package/typings/index.d.ts +2 -0
  78. package/typings/rules/index.d.ts +22 -0
  79. package/typings/rules/is-any.d.ts +5 -0
  80. package/typings/rules/is-array.d.ts +7 -0
  81. package/typings/rules/is-boolean.d.ts +7 -0
  82. package/typings/rules/is-date.d.ts +19 -0
  83. package/typings/rules/is-empty.d.ts +13 -0
  84. package/typings/rules/is-enum.d.ts +9 -0
  85. package/typings/rules/is-integer.d.ts +7 -0
  86. package/typings/rules/is-matches.d.ts +9 -0
  87. package/typings/rules/is-null.d.ts +16 -0
  88. package/typings/rules/is-number.d.ts +7 -0
  89. package/typings/rules/is-object-id.d.ts +10 -0
  90. package/typings/rules/is-object.d.ts +22 -0
  91. package/typings/rules/is-record.d.ts +7 -0
  92. package/typings/rules/is-string.d.ts +42 -0
  93. package/typings/rules/is-tuple.d.ts +27 -0
  94. package/typings/rules/length.d.ts +21 -0
  95. package/typings/rules/optional.d.ts +17 -0
  96. package/typings/rules/pipe.d.ts +11 -0
  97. package/typings/rules/range.d.ts +48 -0
  98. package/typings/rules/string-formats.d.ts +140 -0
  99. package/typings/rules/union.d.ts +5 -0
  100. package/typings/rules/utilities.d.ts +11 -0
  101. package/lib/ArrayType.d.ts +0 -5
  102. package/lib/ArrayType.js +0 -43
  103. package/lib/DataType.d.ts +0 -25
  104. package/lib/DataType.js +0 -214
  105. package/lib/ObjectType.d.ts +0 -5
  106. package/lib/ObjectType.js +0 -78
  107. package/lib/SchemaError.d.ts +0 -3
  108. package/lib/SchemaError.js +0 -17
  109. package/lib/UnionType.d.ts +0 -5
  110. package/lib/UnionType.js +0 -54
  111. package/lib/Valgen.d.ts +0 -88
  112. package/lib/Valgen.js +0 -289
  113. package/lib/ValidationError.d.ts +0 -2
  114. package/lib/ValidationError.js +0 -4
  115. package/lib/factories/AnyFactory.d.ts +0 -28
  116. package/lib/factories/AnyFactory.js +0 -73
  117. package/lib/factories/ArrayFactory.d.ts +0 -16
  118. package/lib/factories/ArrayFactory.js +0 -148
  119. package/lib/factories/Base64Factory.d.ts +0 -12
  120. package/lib/factories/Base64Factory.js +0 -31
  121. package/lib/factories/BooleanFactory.d.ts +0 -12
  122. package/lib/factories/BooleanFactory.js +0 -49
  123. package/lib/factories/DateFactory.d.ts +0 -40
  124. package/lib/factories/DateFactory.js +0 -239
  125. package/lib/factories/FunctionFactory.d.ts +0 -12
  126. package/lib/factories/FunctionFactory.js +0 -28
  127. package/lib/factories/IntegerFactory.d.ts +0 -14
  128. package/lib/factories/IntegerFactory.js +0 -33
  129. package/lib/factories/NilFactory.d.ts +0 -4
  130. package/lib/factories/NilFactory.js +0 -20
  131. package/lib/factories/NumberFactory.d.ts +0 -36
  132. package/lib/factories/NumberFactory.js +0 -178
  133. package/lib/factories/ObjectFactory.d.ts +0 -38
  134. package/lib/factories/ObjectFactory.js +0 -326
  135. package/lib/factories/StringFactory.d.ts +0 -16
  136. package/lib/factories/StringFactory.js +0 -94
  137. package/lib/factories/UnionFactory.d.ts +0 -13
  138. package/lib/factories/UnionFactory.js +0 -62
  139. package/lib/index.d.ts +0 -19
  140. package/lib/index.js +0 -37
@@ -0,0 +1,63 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Checks if value is an empty. Value should be string, array, set, map or object
4
+ * @validator isEmpty
5
+ */
6
+ export function isEmpty(options) {
7
+ return validator('isEmpty', function (input, context) {
8
+ if (input != null) {
9
+ if (typeof input === 'string') {
10
+ if (!input)
11
+ return input;
12
+ }
13
+ else if (Array.isArray(input)) {
14
+ if (!input.length)
15
+ return input;
16
+ }
17
+ else if (input instanceof Set) {
18
+ if (!input.size)
19
+ return input;
20
+ }
21
+ else if (input instanceof Map) {
22
+ if (!input.size)
23
+ return input;
24
+ }
25
+ else if (typeof input === 'object') {
26
+ if (!Object.keys(input).length)
27
+ return input;
28
+ }
29
+ }
30
+ context.failure(`{{label}} is not empty`);
31
+ }, options);
32
+ }
33
+ /**
34
+ * Checks if value is a not empty. Value should be string, array, set, map or object
35
+ * @validator isNotEmpty
36
+ */
37
+ export function isNotEmpty(options) {
38
+ return validator('isNotEmpty', function (input, context) {
39
+ if (input != null) {
40
+ if (typeof input === 'string') {
41
+ if (input)
42
+ return input;
43
+ }
44
+ else if (Array.isArray(input)) {
45
+ if (input.length)
46
+ return input;
47
+ }
48
+ else if (input instanceof Set) {
49
+ if (input.size)
50
+ return input;
51
+ }
52
+ else if (input instanceof Map) {
53
+ if (input.size)
54
+ return input;
55
+ }
56
+ else if (typeof input === 'object') {
57
+ if (Object.keys(input).length)
58
+ return input;
59
+ }
60
+ }
61
+ context.failure(`{{label}} is empty`);
62
+ }, options);
63
+ }
@@ -0,0 +1,26 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Validates if given value is one of enum values.
4
+ * @validator isEnum
5
+ */
6
+ export function isEnum(values, options) {
7
+ const caseInSensitive = !!(options?.caseInSensitive);
8
+ const enumName = options?.enumName;
9
+ // Prepare an object for fast lookup
10
+ const valObj = (Array.isArray(values) ? values : [values])
11
+ .reduce((a, v) => {
12
+ if (typeof v === 'string' && caseInSensitive)
13
+ a[v.toUpperCase()] = true;
14
+ else
15
+ a[v] = true;
16
+ return a;
17
+ }, {});
18
+ return validator('isEnum', function (input, context) {
19
+ if (input != null && valObj[typeof input === 'string' && caseInSensitive ? input.toUpperCase() : input])
20
+ return input;
21
+ context.failure({
22
+ message: `Value must be one of enumeration member${enumName ? ` (${enumName})` : ''}`,
23
+ enum: enumName
24
+ });
25
+ }, options);
26
+ }
@@ -0,0 +1,22 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Validates if value is "integer".
4
+ * Converts input value to integer number if coerce option is set to 'true'.
5
+ * @validator isInteger
6
+ */
7
+ export function isInteger(options) {
8
+ return validator('isInteger', function (input, context) {
9
+ if (input != null && typeof input !== 'number' && context.coerce) {
10
+ if (typeof input === 'string')
11
+ input = parseFloat(input);
12
+ if (typeof input === 'bigint') {
13
+ const v = Number(input);
14
+ if (input === BigInt(v))
15
+ input = v;
16
+ }
17
+ }
18
+ if (typeof input === 'number' && !isNaN(input) && Number.isInteger(input))
19
+ return input;
20
+ context.failure(`{{label}} is not a valid integer number`);
21
+ }, options);
22
+ }
@@ -0,0 +1,20 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Coerces given value to "UUID" format or returns undefined if nullish
4
+ * @validator uuid
5
+ */
6
+ export function isMatches(format, options) {
7
+ const regExp = format instanceof RegExp ? format : new RegExp(format);
8
+ const formatName = options?.formatName;
9
+ return validator('matches', function (input, context) {
10
+ if (input == null)
11
+ return;
12
+ if (typeof input === 'string' && regExp.test(input))
13
+ return input;
14
+ context.failure({
15
+ message: `{{label}} does not match ${formatName || 'requested'} format`,
16
+ format,
17
+ formatName
18
+ });
19
+ }, options);
20
+ }
@@ -0,0 +1,34 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Validates if value is "null".
4
+ * @validator isNull
5
+ */
6
+ export function isNull(options) {
7
+ return validator('isNull', function (input, context) {
8
+ if (input === null)
9
+ return input;
10
+ context.failure(`{{label}} is not null`);
11
+ }, options);
12
+ }
13
+ /**
14
+ * Validates if value is not "undefined" nor "null"
15
+ * @validator isDefined
16
+ */
17
+ export function isDefined(options) {
18
+ return validator('is-defined', function (input, context) {
19
+ if (input !== undefined)
20
+ return input;
21
+ context.failure(`{{label}} is not defined`);
22
+ }, options);
23
+ }
24
+ /**
25
+ * Validates if value is "undefined"
26
+ * @validator isNotDefined
27
+ */
28
+ export function isUndefined(options) {
29
+ return validator('isUndefined', function (input, context) {
30
+ if (input === undefined)
31
+ return;
32
+ context.failure(`{{label}} defined`);
33
+ }, options);
34
+ }
@@ -0,0 +1,22 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Validates if value is "number".
4
+ * Converts input value to number if coerce option is set to 'true'.
5
+ * @validator isNumber
6
+ */
7
+ export function isNumber(options) {
8
+ return validator('isNumber', function (input, context) {
9
+ if (input != null && typeof input !== 'number' && context.coerce) {
10
+ if (typeof input === 'string')
11
+ input = parseFloat(input);
12
+ if (typeof input === 'bigint') {
13
+ const v = Number(input);
14
+ if (input === BigInt(v))
15
+ input = v;
16
+ }
17
+ }
18
+ if (typeof input === 'number' && !isNaN(input))
19
+ return input;
20
+ context.failure(`{{label}} not a valid number`);
21
+ }, options);
22
+ }
@@ -0,0 +1,21 @@
1
+ import validatorJS from 'validator';
2
+ import { validator } from '../core/index.js';
3
+ /**
4
+ * Validates if value is an "ObjectId".
5
+ * @validator isObjectId
6
+ */
7
+ export function isObjectId(options) {
8
+ return validator('isObjectId', function (input, context) {
9
+ if (input != null &&
10
+ (_isObjectIdValue(input) ||
11
+ (typeof input === 'object' &&
12
+ typeof input.toHexString === 'function' &&
13
+ _isObjectIdValue(input.toHexString()))))
14
+ return input;
15
+ context.failure(`{{label}} is not a valid ObjectId`);
16
+ }, options);
17
+ }
18
+ function _isObjectIdValue(input) {
19
+ return (input instanceof Uint8Array && input.length === 12) ||
20
+ (typeof input === 'string' && input.length === 24 && validatorJS.isHexadecimal(input));
21
+ }
@@ -0,0 +1,99 @@
1
+ import { isValidator, kValidatorFn, validator } from '../core/index.js';
2
+ /**
3
+ * Validates object according to schema
4
+ * Converts properties according to schema rules if coerce option is set to 'true'.
5
+ * @validator isObject
6
+ */
7
+ export function isObject(schema, options) {
8
+ const ctor = options?.ctor;
9
+ const ctorName = options?.name || ctor?.name;
10
+ const additionalFields = options?.additionalFields ?? false;
11
+ const caseInSensitive = !!options?.caseInSensitive;
12
+ const detectCircular = !!options?.detectCircular;
13
+ if (options) {
14
+ delete options.name;
15
+ delete options.ctor;
16
+ delete options.additionalFields;
17
+ delete options.caseInSensitive;
18
+ delete options.detectCircular;
19
+ }
20
+ const propertyRules = {};
21
+ const propertyOptions = {};
22
+ Object.keys(schema).forEach(k => {
23
+ const n = schema[k];
24
+ const key = caseInSensitive ? k.toLowerCase() : k;
25
+ if (Array.isArray(n)) {
26
+ if (!isValidator(n[0]))
27
+ throw new TypeError(`Invalid tuple definition in validation schema (${k})`);
28
+ propertyRules[key] = n[0];
29
+ propertyOptions[key] = { as: k, ...n[1] };
30
+ }
31
+ else if (isValidator(n)) {
32
+ propertyRules[key] = n;
33
+ propertyOptions[key] = { as: k };
34
+ }
35
+ else
36
+ throw new TypeError(`Invalid definition in validation schema (${k})`);
37
+ });
38
+ const schemaKeys = Object.keys(propertyRules);
39
+ const _rule = validator('isObject', function (input, context) {
40
+ if (!(input && typeof input === 'object')) {
41
+ context.failure(`{{label}} must be an object`);
42
+ return;
43
+ }
44
+ const keyMap = [...Object.keys(input), ...schemaKeys]
45
+ .reduce((a, k) => {
46
+ if (caseInSensitive)
47
+ a[k.toLowerCase()] = k;
48
+ else
49
+ a[k] = k;
50
+ return a;
51
+ }, {});
52
+ const keys = Object.keys(keyMap);
53
+ const l = keys.length;
54
+ let i = 0;
55
+ let inputKey;
56
+ let schemaKey;
57
+ let v;
58
+ let _propRule;
59
+ const out = {};
60
+ if (ctor)
61
+ Object.setPrototypeOf(out, ctor.prototype);
62
+ if (detectCircular) {
63
+ context.circMap = context.circMap || new Map();
64
+ if (context.circMap.has(input))
65
+ return context.circMap.get(input);
66
+ context.circMap.set(input, out);
67
+ }
68
+ const rootName = context.root?.input.context;
69
+ const location = context.input.location || '';
70
+ // Iterate object keys and perform rules
71
+ for (i = 0; i < l; i++) {
72
+ inputKey = keys[i];
73
+ schemaKey = keyMap[inputKey];
74
+ v = input[inputKey];
75
+ _propRule = propertyRules[schemaKey] ||
76
+ (isValidator(additionalFields) ? additionalFields : undefined);
77
+ if (_propRule) {
78
+ const subCtx = context.extend(_propRule);
79
+ if (ctorName) {
80
+ if (rootName && rootName !== ctorName)
81
+ subCtx.input.root = rootName;
82
+ subCtx.input.context = ctorName;
83
+ }
84
+ subCtx.input.value = v;
85
+ subCtx.input.label = propertyOptions[schemaKey]?.label || schemaKey;
86
+ subCtx.input.location = location + (location ? '.' : '') + schemaKey;
87
+ subCtx.input.property = schemaKey;
88
+ v = _propRule[kValidatorFn](v, subCtx, _propRule);
89
+ }
90
+ else if (v !== undefined && !additionalFields)
91
+ context.failure(`${ctorName || 'Object'} does not accept additional fields`);
92
+ if (v !== undefined)
93
+ out[propertyOptions[schemaKey]?.as || schemaKey] = v;
94
+ }
95
+ return context.errors.length ? undefined : out;
96
+ }, options);
97
+ _rule.schema = schema;
98
+ return _rule;
99
+ }
@@ -0,0 +1,37 @@
1
+ import { kValidatorFn, validator, } from '../core/index.js';
2
+ /**
3
+ * Validates record object according to given "key" and "value" rules
4
+ * Converts properties according to rules if coerce option is set to 'true'.
5
+ * @validator isRecord
6
+ */
7
+ export function isRecord(keyRule, valueRule, options) {
8
+ return validator('isRecord', function (input, context) {
9
+ if (!(input && typeof input === 'object')) {
10
+ context.failure(`{{label}} is not an object`);
11
+ return;
12
+ }
13
+ const location = context.input.location || '';
14
+ const keyContext = context.extend(keyRule);
15
+ const valueContext = context.extend(valueRule);
16
+ const keys = Object.keys(input);
17
+ const l = keys.length;
18
+ let i;
19
+ let k;
20
+ let v;
21
+ const out = {};
22
+ for (i = 0; i < l; i++) {
23
+ k = keys[i];
24
+ v = input[k];
25
+ keyContext.input.value = k;
26
+ keyContext.input.property = '@' + k;
27
+ keyContext.input.location = location + (location ? '.@' : '@') + k;
28
+ k = keyRule[kValidatorFn](k, keyContext, keyRule);
29
+ valueContext.input.value = v;
30
+ valueContext.input.property = k;
31
+ valueContext.input.location = location + (location ? '.' : '') + k;
32
+ v = valueRule[kValidatorFn](v, valueContext, valueRule);
33
+ out[k] = v;
34
+ }
35
+ return context.errors.length ? undefined : out;
36
+ }, options);
37
+ }
@@ -0,0 +1,70 @@
1
+ import { validator } from '../core/index.js';
2
+ /**
3
+ * Validates if value is "string".
4
+ * Converts input value to string if coerce option is set to 'true'.
5
+ * @validator isString
6
+ */
7
+ export function isString(options) {
8
+ return validator('isString', function (input, context) {
9
+ if (input != null && typeof input !== 'string' && context.coerce) {
10
+ if (typeof input === 'object') {
11
+ if (typeof input.toJSON === 'function')
12
+ input = input.toJSON();
13
+ else
14
+ input = JSON.stringify(input);
15
+ }
16
+ else
17
+ input = String(input);
18
+ }
19
+ if (typeof input === 'string')
20
+ return input;
21
+ context.failure(`{{label}} is not a string`);
22
+ }, options);
23
+ }
24
+ export function stringReplace(searchValue, replacer) {
25
+ return validator('stringReplace', function (input) {
26
+ if (input == null)
27
+ return input;
28
+ return String(input).replace(searchValue, replacer);
29
+ });
30
+ }
31
+ export function stringSplit(splitter, limit) {
32
+ return validator('stringSplit', function (input) {
33
+ if (input == null)
34
+ return input;
35
+ return String(input).split(splitter, limit);
36
+ });
37
+ }
38
+ /**
39
+ * Removes whitespace from both ends of a string
40
+ * @validator trim
41
+ */
42
+ export function trim() {
43
+ return validator('trim', function (input) {
44
+ if (input == null)
45
+ return input;
46
+ return String(input).trim();
47
+ });
48
+ }
49
+ // *************************************************************
50
+ /**
51
+ * Removes whitespace from the end of a string
52
+ * @validator trimEnd
53
+ */
54
+ export const trimEnd = () => trimEndRule;
55
+ const trimEndRule = validator('trimEnd', function (input) {
56
+ if (input == null)
57
+ return input;
58
+ return String(input).trimEnd();
59
+ });
60
+ // *************************************************************
61
+ /**
62
+ * Removes whitespace from the beginning of a string
63
+ * @validator trimStart
64
+ */
65
+ export const trimStart = () => trimStartRule;
66
+ const trimStartRule = validator('trimStart', function (input) {
67
+ if (input == null)
68
+ return input;
69
+ return String(input).trimStart();
70
+ });
@@ -0,0 +1,28 @@
1
+ import { kValidatorFn, validator } from '../core/index.js';
2
+ export function isTuple(items, options) {
3
+ return validator('isTuple', function (input, context) {
4
+ if (input != null && context.coerce && !Array.isArray(input))
5
+ input = [input];
6
+ if (!Array.isArray(input)) {
7
+ context.failure(`{{label}} is not a valid tuple`);
8
+ return;
9
+ }
10
+ const location = context.input.location || '';
11
+ let itemRule;
12
+ let i;
13
+ const l = input.length;
14
+ const out = [];
15
+ const nl = items.length;
16
+ for (i = 0; i < l && i < nl; i++) {
17
+ itemRule = items[i];
18
+ const itemContext = context.extend(itemRule);
19
+ itemContext.input.value = input[i];
20
+ itemContext.input.label = ((context.input.label || context.input.property) || 'Item') +
21
+ `[${i}]`;
22
+ itemContext.input.property = i;
23
+ itemContext.input.location = location + '[' + i + ']';
24
+ out.push(itemRule[kValidatorFn](input[i], itemContext, itemRule) ?? null);
25
+ }
26
+ return context.errors.length ? undefined : out;
27
+ }, options);
28
+ }
@@ -0,0 +1,35 @@
1
+ import { validator } from '../core/index.js';
2
+ import { allOf, pipe } from './pipe.js';
3
+ import { isGte, isLte } from './range.js';
4
+ /**
5
+ * Returns length of an Array, String, ArrayBuffer, Buffer or any object with the "length" property.
6
+ * @validator getLength
7
+ */
8
+ export const extractLength = () => extractLengthRule;
9
+ const extractLengthRule = validator('extractLength', function (input, context) {
10
+ if (typeof input === 'string')
11
+ return input.length;
12
+ if (Array.isArray(input))
13
+ return input.length;
14
+ if (input instanceof ArrayBuffer)
15
+ return input.byteLength;
16
+ if (input && typeof input === 'object' && typeof input.length === 'number')
17
+ return input.length;
18
+ if (input && typeof input === 'object' && typeof input.size === 'number')
19
+ return input.size;
20
+ context.failure(`Unable to extract length of {{label}}`);
21
+ });
22
+ /**
23
+ * Checks the length is at least "minValue"
24
+ * @validator lengthMin
25
+ */
26
+ export const lengthMin = (minValue) => allOf(pipe(extractLength(), isGte(minValue, {
27
+ onFail: () => `The length of {{label}} must be at least ${minValue}`
28
+ })));
29
+ /**
30
+ * Checks if the length is at most "maxValue"
31
+ * @validator charLengthMax
32
+ */
33
+ export const lengthMax = (maxValue) => allOf(pipe(extractLength(), isLte(maxValue, {
34
+ onFail: () => `The length of {{label}} must be at most ${maxValue}`
35
+ })));
@@ -0,0 +1,38 @@
1
+ import { kValidatorFn, validator } from '../core/index.js';
2
+ /**
3
+ * Makes sub-rule optional
4
+ * @validator optional
5
+ */
6
+ export function optional(nested, options) {
7
+ return validator('optional', function (input, context) {
8
+ if (input == null)
9
+ return input;
10
+ return nested[kValidatorFn](input, context, nested);
11
+ }, options);
12
+ }
13
+ /**
14
+ * Makes sub-rule required
15
+ * @validator required
16
+ */
17
+ export function required(nested, options) {
18
+ return validator('required', function (input, context) {
19
+ if (input == null) {
20
+ context.failure(`{{label}} is required`);
21
+ return;
22
+ }
23
+ return nested[kValidatorFn](input, context, nested);
24
+ }, options);
25
+ }
26
+ /**
27
+ * Validates if property exists
28
+ * @validator exists
29
+ */
30
+ export function exists(options) {
31
+ return validator('exists', function (input, context) {
32
+ if (input !== undefined ||
33
+ (context.input.value && context.parent &&
34
+ Object.getOwnPropertyDescriptor(context.input.value, context.input.property)))
35
+ return input;
36
+ context.failure(`{{label}} must exist`);
37
+ }, options);
38
+ }
@@ -0,0 +1,38 @@
1
+ import { kValidatorFn, validator } from '../core/index.js';
2
+ /**
3
+ *
4
+ * @validator pipe
5
+ */
6
+ export function pipe(...rules) {
7
+ const l = rules.length;
8
+ return validator('pipe', function (input, context) {
9
+ let i;
10
+ let c;
11
+ let v = input;
12
+ for (i = 0; i < l; i++) {
13
+ c = rules[i];
14
+ const subContext = context.extend(c);
15
+ v = c[kValidatorFn](v, subContext, c);
16
+ if (context.errors.length)
17
+ return;
18
+ }
19
+ return v;
20
+ });
21
+ }
22
+ /**
23
+ * Test given value against to all codecs and returns original input
24
+ * @validator allOf
25
+ */
26
+ export function allOf(...rules) {
27
+ return validator('allOf', function (input, context) {
28
+ let i;
29
+ let c;
30
+ const l = rules.length;
31
+ for (i = 0; i < l; i++) {
32
+ c = rules[i];
33
+ const subContext = context.extend(c);
34
+ c[kValidatorFn](input, subContext, c);
35
+ }
36
+ return input;
37
+ });
38
+ }
@@ -0,0 +1,81 @@
1
+ import { validator } from '../core/index.js';
2
+ export function isGt(minValue, options) {
3
+ return validator('isGt', function (input, context) {
4
+ if ((typeof minValue === 'number' || typeof minValue === 'bigint') &&
5
+ (typeof input === 'number' || typeof input === 'bigint') &&
6
+ input > minValue)
7
+ return input;
8
+ if (minValue instanceof Date && input instanceof Date && input > minValue)
9
+ return input;
10
+ if (typeof minValue === 'string' && typeof input === 'string' &&
11
+ (input > minValue ||
12
+ (options?.caseInsensitive && input.toLowerCase() > minValue.toLowerCase())))
13
+ return input;
14
+ context.failure(`{{label}} must be greater than ${(typeof minValue === 'string' ? `"${minValue}"` : minValue)}`);
15
+ }, options);
16
+ }
17
+ export function isGte(minValue, options) {
18
+ return validator('isGte', function (input, context) {
19
+ if ((typeof minValue === 'number' || typeof minValue === 'bigint') &&
20
+ (typeof input === 'number' || typeof input === 'bigint') &&
21
+ input >= minValue)
22
+ return input;
23
+ if (minValue instanceof Date && input instanceof Date && input >= minValue)
24
+ return input;
25
+ if (typeof minValue === 'string' && typeof input === 'string' &&
26
+ (input >= minValue ||
27
+ (options?.caseInsensitive && input.toLowerCase() >= minValue.toLowerCase())))
28
+ return input;
29
+ context.failure(`{{label}} must be greater than or equal to ${(typeof minValue === 'string' ? `"${minValue}"` : minValue)}`);
30
+ }, options);
31
+ }
32
+ export function isLt(maxValue, options) {
33
+ return validator('isLt', function (input, context) {
34
+ if ((typeof maxValue === 'number' || typeof maxValue === 'bigint') &&
35
+ (typeof input === 'number' || typeof input === 'bigint') &&
36
+ input < maxValue)
37
+ return input;
38
+ if (maxValue instanceof Date && input instanceof Date && input < maxValue)
39
+ return input;
40
+ if (typeof maxValue === 'string' && typeof input === 'string' &&
41
+ (input < maxValue ||
42
+ (options?.caseInsensitive && input.toLowerCase() < maxValue.toLowerCase())))
43
+ return input;
44
+ context.failure(`{{label}} must be lover than ${(typeof maxValue === 'string' ? `"${maxValue}"` : maxValue)}`);
45
+ }, options);
46
+ }
47
+ export function isLte(maxValue, options) {
48
+ return validator('isLt', function (input, context) {
49
+ if ((typeof maxValue === 'number' || typeof maxValue === 'bigint') &&
50
+ (typeof input === 'number' || typeof input === 'bigint') &&
51
+ input <= maxValue)
52
+ return input;
53
+ if (maxValue instanceof Date && input instanceof Date && input <= maxValue)
54
+ return input;
55
+ if (typeof maxValue === 'string' && typeof input === 'string' &&
56
+ (input <= maxValue ||
57
+ (options?.caseInsensitive && input.toLowerCase() <= maxValue.toLowerCase())))
58
+ return input;
59
+ context.failure(`{{label}} must be lover than or equal to ${(typeof maxValue === 'string' ? `"${maxValue}"` : maxValue)}`);
60
+ }, options);
61
+ }
62
+ /**
63
+ * Checks if value is between minValue and maxValue
64
+ * @validator range
65
+ */
66
+ export function range(minValue, maxValue, options) {
67
+ return validator('range', function (input, context) {
68
+ if ((typeof minValue === 'number' || typeof minValue === 'bigint') &&
69
+ (typeof maxValue === 'number' || typeof maxValue === 'bigint') &&
70
+ (typeof input === 'number' || typeof input === 'bigint') &&
71
+ input >= minValue && input <= maxValue)
72
+ return input;
73
+ if (minValue instanceof Date && maxValue instanceof Date &&
74
+ input instanceof Date && input >= minValue && input <= maxValue)
75
+ return input;
76
+ if (typeof minValue === 'string' && typeof maxValue === 'string' &&
77
+ typeof input === 'string' && input >= minValue && input <= maxValue)
78
+ return input;
79
+ context.failure(`{{label}} must be between ${minValue} and ${maxValue}`);
80
+ }, options);
81
+ }