@astral/validations 4.6.1 → 4.7.0

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 (55) hide show
  1. package/README.md +40 -0
  2. package/array/array.d.ts +1 -8
  3. package/boolean/boolean.d.ts +1 -8
  4. package/core/composeAsync/composeAsync.d.ts +6 -0
  5. package/core/composeAsync/composeAsync.js +24 -0
  6. package/core/composeAsync/index.d.ts +1 -0
  7. package/core/composeAsync/index.js +1 -0
  8. package/core/errors/constants.d.ts +2 -0
  9. package/core/errors/constants.js +5 -0
  10. package/core/errors/index.d.ts +1 -0
  11. package/core/errors/index.js +1 -0
  12. package/core/guard/createGuard/createGuard.d.ts +21 -24
  13. package/core/guard/createGuard/createGuard.js +8 -27
  14. package/core/guard/types.d.ts +18 -0
  15. package/core/guard/types.js +1 -0
  16. package/core/index.d.ts +1 -0
  17. package/core/index.js +1 -0
  18. package/core/logger/index.d.ts +1 -0
  19. package/core/logger/index.js +1 -0
  20. package/core/logger/logger.d.ts +6 -0
  21. package/core/logger/logger.js +9 -0
  22. package/core/rule/callAsyncRule/callAsyncRule.d.ts +8 -0
  23. package/core/rule/callAsyncRule/callAsyncRule.js +25 -0
  24. package/core/rule/callAsyncRule/index.d.ts +1 -0
  25. package/core/rule/callAsyncRule/index.js +1 -0
  26. package/core/rule/index.d.ts +1 -0
  27. package/core/rule/index.js +1 -0
  28. package/core/rule/types.d.ts +8 -0
  29. package/date/date.d.ts +1 -8
  30. package/index.d.ts +2 -2
  31. package/index.js +2 -2
  32. package/number/number.d.ts +1 -8
  33. package/object/index.d.ts +1 -0
  34. package/object/index.js +1 -0
  35. package/object/object.d.ts +1 -8
  36. package/object/objectAsync/index.d.ts +1 -0
  37. package/object/objectAsync/index.js +1 -0
  38. package/object/objectAsync/objectAsync.d.ts +61 -0
  39. package/object/objectAsync/objectAsync.js +71 -0
  40. package/package.json +1 -1
  41. package/partial/partial.d.ts +3 -10
  42. package/string/index.d.ts +1 -0
  43. package/string/index.js +1 -0
  44. package/string/string.d.ts +1 -8
  45. package/string/string.js +2 -1
  46. package/string/stringAsync/index.d.ts +1 -0
  47. package/string/stringAsync/index.js +1 -0
  48. package/string/stringAsync/stringAsync.d.ts +6 -0
  49. package/string/stringAsync/stringAsync.js +23 -0
  50. package/string/utils/index.d.ts +1 -0
  51. package/string/utils/index.js +1 -0
  52. package/string/utils/isString/index.d.ts +1 -0
  53. package/string/utils/isString/index.js +1 -0
  54. package/string/utils/isString/isString.d.ts +1 -0
  55. package/string/utils/isString/isString.js +1 -0
package/README.md CHANGED
@@ -65,6 +65,7 @@
65
65
  - [when. Условная валидация](#when-условная-валидация)
66
66
  - [transform](#transform)
67
67
  - [or](#or)
68
+ - [Async](#async)
68
69
  - [Integrations](#integrations)
69
70
  - [react-hook-form](#react-hook-form)
70
71
  - [Guides](#guides)
@@ -1464,6 +1465,45 @@ validate(new Date())
1464
1465
 
1465
1466
  ---
1466
1467
 
1468
+ # Async
1469
+ Пакет поддерживает асинхронную валидацию.
1470
+
1471
+ Guard, поддерживающие асинхронную валидацию имеют постфиксы ```async```:
1472
+ - ```objectAsync```
1473
+ - ```stringAsync```
1474
+
1475
+ Пример:
1476
+
1477
+ ```ts
1478
+ type Values = {
1479
+ nickname: string;
1480
+ phone: string;
1481
+ };
1482
+
1483
+ const validate = objectAsync<Values>({
1484
+ phone: string(),
1485
+ nickname: stringAsync(min(3), async (value, ctx) => {
1486
+ const nicknameIsAvailable = await checkNickname(value);
1487
+
1488
+ if (nicknameIsAvailable) {
1489
+ return undefined;
1490
+ }
1491
+
1492
+ return ctx.createError({
1493
+ code: 'nickname-available',
1494
+ message: 'Nickname занят',
1495
+ });
1496
+ }),
1497
+ });
1498
+
1499
+ const result = await validate({ phone: '79308999999', nickname: 'Vasya' });
1500
+
1501
+ // { nickname: 'Nickname занят' }
1502
+ toPrettyError(result);
1503
+ ```
1504
+
1505
+ ---
1506
+
1467
1507
  # Integrations
1468
1508
 
1469
1509
  ## react-hook-form
package/array/array.d.ts CHANGED
@@ -12,11 +12,4 @@ import { ValidationRule } from '../core';
12
12
  * validateArray(value);
13
13
  * ```
14
14
  */
15
- export declare const array: <TItem extends unknown, TLastSchemaValues extends Record<string, unknown> = {}>(...rules: ValidationRule<TItem[], TLastSchemaValues>[]) => {
16
- (value: unknown, prevCtx?: import("../core").ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
17
- define(overridesDefOptions: Partial<{}> & {
18
- requiredErrorMessage?: string | undefined;
19
- typeErrorMessage?: string | undefined;
20
- isOptional?: boolean | undefined;
21
- }): any;
22
- };
15
+ export declare const array: <TItem extends unknown, TLastSchemaValues extends Record<string, unknown> = {}>(...rules: ValidationRule<TItem[], TLastSchemaValues>[]) => import("../core").Guard<TLastSchemaValues, {}>;
@@ -10,11 +10,4 @@ import { ValidationRule } from '../core';
10
10
  * validate(true);
11
11
  * ```
12
12
  */
13
- export declare const boolean: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<boolean, TLastSchemaValues>[]) => {
14
- (value: unknown, prevCtx?: import("../core").ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
15
- define(overridesDefOptions: Partial<{}> & {
16
- requiredErrorMessage?: string | undefined;
17
- typeErrorMessage?: string | undefined;
18
- isOptional?: boolean | undefined;
19
- }): any;
20
- };
13
+ export declare const boolean: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<boolean, TLastSchemaValues>[]) => import("../core").Guard<TLastSchemaValues, {}>;
@@ -0,0 +1,6 @@
1
+ import { AsyncIndependentValidationRule, AsyncValidationRule, IndependentValidationRule, ValidationRule } from '../rule';
2
+ /**
3
+ * Объединяет переданные асинхронные правила в цепочку правил, останавливает выполнение цепочки, если появилась ошибка. Выполняет правила слева направо
4
+ * @example composeAsync(stringAsync(), max());
5
+ */
6
+ export declare const composeAsync: <ValidationType, TLastSchemaValues extends Record<string, unknown>>(...rules: (IndependentValidationRule<ValidationType, TLastSchemaValues> | AsyncIndependentValidationRule<ValidationType, TLastSchemaValues> | ValidationRule<ValidationType, TLastSchemaValues> | AsyncValidationRule<ValidationType, TLastSchemaValues>)[]) => AsyncIndependentValidationRule<ValidationType, Record<string, unknown>>;
@@ -0,0 +1,24 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { callAsyncRule, } from '../rule';
11
+ /**
12
+ * Объединяет переданные асинхронные правила в цепочку правил, останавливает выполнение цепочки, если появилась ошибка. Выполняет правила слева направо
13
+ * @example composeAsync(stringAsync(), max());
14
+ */
15
+ export const composeAsync = (...rules) => (value, ctx) => __awaiter(void 0, void 0, void 0, function* () {
16
+ let result;
17
+ for (const rule of rules) {
18
+ result = yield callAsyncRule(rule, value, ctx);
19
+ if (result) {
20
+ break;
21
+ }
22
+ }
23
+ return result;
24
+ });
@@ -0,0 +1 @@
1
+ export * from './composeAsync';
@@ -0,0 +1 @@
1
+ export * from './composeAsync';
@@ -0,0 +1,2 @@
1
+ import { ErrorInfo } from './types';
2
+ export declare const REJECT_PROMISE_ERROR_INFO: ErrorInfo;
@@ -0,0 +1,5 @@
1
+ import { createErrorCode } from './createErrorCode';
2
+ export const REJECT_PROMISE_ERROR_INFO = {
3
+ code: createErrorCode('reject-promise'),
4
+ message: 'Неизвестная ошибка',
5
+ };
@@ -3,3 +3,4 @@ export * from './ArrayError';
3
3
  export * from './ErrorMap';
4
4
  export * from './types';
5
5
  export * from './createErrorCode';
6
+ export * from './constants';
@@ -3,3 +3,4 @@ export * from './ArrayError';
3
3
  export * from './ErrorMap';
4
4
  export * from './types';
5
5
  export * from './createErrorCode';
6
+ export * from './constants';
@@ -1,23 +1,6 @@
1
1
  import { ValidationResult } from '../../types';
2
2
  import { ValidationContext } from '../../context';
3
- type DefOptions<AddDefOptions extends Record<string, unknown>> = Partial<AddDefOptions> & {
4
- /**
5
- * @description Переопределяет дефолтное сообщения ошибки для required
6
- * @example string.define({ requiredMessage: 'ИНН не может быть пустым' })(inn())
7
- */
8
- requiredErrorMessage?: string;
9
- /**
10
- * @description Переопределяет сообщение об ошибке типа
11
- * @example string.define({ typeErrorMessage: 'ИНН не может быть числом' })(inn())
12
- */
13
- typeErrorMessage?: string;
14
- /**
15
- * @description Позволяет выключать проверку на required
16
- * @default false
17
- */
18
- isOptional?: boolean;
19
- };
20
- type GuardValue = unknown;
3
+ import { GuardDefOptions, GuardValue } from '../types';
21
4
  /**
22
5
  * @description Интерфейс функции guard, которая в прототипе содержит метод define
23
6
  */
@@ -28,12 +11,28 @@ export interface Guard<TLastSchemaValues extends Record<string, unknown> = {}, A
28
11
  * @param options - параметры, позволяющие переопределить дефолтные настройки guard
29
12
  * @example string.define({ requiredMessage: 'ИНН не может быть пустым' })(inn())
30
13
  */
31
- define(options: DefOptions<AddDefOptions>): Guard<TLastSchemaValues, AddDefOptions>;
14
+ define(options: GuardDefOptions<AddDefOptions>): Guard<TLastSchemaValues, AddDefOptions>;
15
+ }
16
+ /**
17
+ * @description Интерфейс асинхронной функции guard, которая в прототипе содержит метод define
18
+ */
19
+ export interface AsyncGuard<TLastSchemaValues extends Record<string, unknown> = {}, AddDefOptions extends Record<string, unknown> = {}> {
20
+ (value: GuardValue, ctx?: ValidationContext<TLastSchemaValues>): Promise<ValidationResult>;
21
+ /**
22
+ * @description Функция для создания нового guard с переопределенными дефолтными параметрами. Возвращает новый guard
23
+ * @param options - параметры, позволяющие переопределить дефолтные настройки guard
24
+ * @example string.define({ requiredMessage: 'ИНН не может быть пустым' })(inn())
25
+ */
26
+ define(options: GuardDefOptions<AddDefOptions>): AsyncGuard<TLastSchemaValues, AddDefOptions>;
32
27
  }
33
28
  /**
34
29
  * @description Функция, которая позволяет определять частную логику для guard
35
30
  */
36
- type GuardExecutor<AddDefOptions extends Record<string, unknown>> = (value: unknown, ctx: ValidationContext<Record<string, unknown>>, defOptions: DefOptions<AddDefOptions>) => ValidationResult;
31
+ type GuardExecutor<AddDefOptions extends Record<string, unknown>> = (value: unknown, ctx: ValidationContext<Record<string, unknown>>, defOptions: GuardDefOptions<AddDefOptions>) => ValidationResult;
32
+ /**
33
+ * @description Функция, которая позволяет определять частную логику для guard
34
+ */
35
+ type AsyncGuardExecutor<AddDefOptions extends Record<string, unknown>> = (value: unknown, ctx: ValidationContext<Record<string, unknown>>, defOptions: GuardDefOptions<AddDefOptions>) => Promise<ValidationResult>;
37
36
  /**
38
37
  * @description Создает guard. Guard - функция, проверяющая тип значения
39
38
  * По-дефолту проверяет value на required. Для выключения required необходимо использовать optional().
@@ -50,8 +49,6 @@ type GuardExecutor<AddDefOptions extends Record<string, unknown>> = (value: unkn
50
49
  * });
51
50
  * ```
52
51
  */
53
- export declare const createGuard: <TLastSchemaValues extends Record<string, unknown>, AddDefOptions extends Record<string, unknown> = {}>(executeGuard: GuardExecutor<AddDefOptions>) => {
54
- (value: unknown, prevCtx?: ValidationContext<TLastSchemaValues> | undefined): ValidationResult;
55
- define(overridesDefOptions: DefOptions<AddDefOptions>): any;
56
- };
52
+ export declare function createGuard<TLastSchemaValues extends Record<string, unknown>, AddDefOptions extends Record<string, unknown> = {}>(executor: GuardExecutor<AddDefOptions>): Guard<TLastSchemaValues, AddDefOptions>;
53
+ export declare function createGuard<TLastSchemaValues extends Record<string, unknown>, AddDefOptions extends Record<string, unknown> = {}>(executor: AsyncGuardExecutor<AddDefOptions>): AsyncGuard<TLastSchemaValues, AddDefOptions>;
57
54
  export {};
@@ -1,41 +1,22 @@
1
- import { REQUIRED_ERROR_INFO, required } from '../../rule';
1
+ import { required } from '../../rule';
2
2
  import { createContext } from '../../context';
3
- import { compose } from '../../compose';
4
- /**
5
- * @description Создает guard. Guard - функция, проверяющая тип значения
6
- * По-дефолту проверяет value на required. Для выключения required необходимо использовать optional().
7
- * После первого вызова guard в прототипу функции становится доступен метод define, который позволяет переопределить дефолтное поведение guard (например, изменить текст для required правила)
8
- * @example
9
- * ```ts
10
- * const string = <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<string, TValues>[]) =>
11
- * createGuard<string, TValues>((value, ctx) => {
12
- * if (typeof value !== 'string') {
13
- * return ctx.createError({ code: 'custom error', message: 'Не строка' });
14
- * }
15
- *
16
- * return compose<string, TValues>(...rules)(value, ctx);
17
- * });
18
- * ```
19
- */
20
- export const createGuard = (executeGuard) => {
3
+ export function createGuard(executor) {
21
4
  // выделено в отдельную именованную функцию для того, чтобы ее можно было рекурсивно вызывать в define
22
5
  const createInnerGuard = (defOptions = {}) => {
23
6
  const guard = (value, prevCtx) => {
24
7
  const ctx = createContext(prevCtx,
25
8
  // при создании контекста сейчас не имеет значение какого типа будет ctx.values
26
9
  value);
27
- const validationResult = compose(
28
- // возможность переопределить дефолтный message для required
29
- required({ message: defOptions === null || defOptions === void 0 ? void 0 : defOptions.requiredErrorMessage }), (interValue, interCtx) => executeGuard(interValue, interCtx, defOptions))(value, ctx);
30
- // если включен isOptional режим и required упал с ошибкой, то необходимо проигнорировать ошибку
31
- if ((defOptions === null || defOptions === void 0 ? void 0 : defOptions.isOptional) &&
32
- (validationResult === null || validationResult === void 0 ? void 0 : validationResult.cause.code) === REQUIRED_ERROR_INFO.code) {
10
+ const requiredResult = required({
11
+ message: defOptions === null || defOptions === void 0 ? void 0 : defOptions.requiredErrorMessage,
12
+ })(value, ctx);
13
+ if ((defOptions === null || defOptions === void 0 ? void 0 : defOptions.isOptional) && requiredResult) {
33
14
  return undefined;
34
15
  }
35
- return validationResult;
16
+ return requiredResult || executor(value, ctx, defOptions);
36
17
  };
37
18
  guard.define = (overridesDefOptions) => createInnerGuard(overridesDefOptions);
38
19
  return guard;
39
20
  };
40
21
  return createInnerGuard();
41
- };
22
+ }
@@ -0,0 +1,18 @@
1
+ export type GuardDefOptions<AddDefOptions extends Record<string, unknown>> = Partial<AddDefOptions> & {
2
+ /**
3
+ * @description Переопределяет дефолтное сообщения ошибки для required
4
+ * @example string.define({ requiredMessage: 'ИНН не может быть пустым' })(inn())
5
+ */
6
+ requiredErrorMessage?: string;
7
+ /**
8
+ * @description Переопределяет сообщение об ошибке типа
9
+ * @example string.define({ typeErrorMessage: 'ИНН не может быть числом' })(inn())
10
+ */
11
+ typeErrorMessage?: string;
12
+ /**
13
+ * @description Позволяет выключать проверку на required
14
+ * @default false
15
+ */
16
+ isOptional?: boolean;
17
+ };
18
+ export type GuardValue = unknown;
@@ -0,0 +1 @@
1
+ export {};
package/core/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export * from './errors';
5
5
  export * from './guard';
6
6
  export * from './rule';
7
7
  export * from './compose';
8
+ export * from './composeAsync';
8
9
  export * from './utils';
package/core/index.js CHANGED
@@ -5,4 +5,5 @@ export * from './errors';
5
5
  export * from './guard';
6
6
  export * from './rule';
7
7
  export * from './compose';
8
+ export * from './composeAsync';
8
9
  export * from './utils';
@@ -0,0 +1 @@
1
+ export * from './logger';
@@ -0,0 +1 @@
1
+ export * from './logger';
@@ -0,0 +1,6 @@
1
+ declare class Logger {
2
+ private packageName;
3
+ error: (message: string, err: Error) => void;
4
+ }
5
+ export declare const logger: Logger;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ class Logger {
2
+ constructor() {
3
+ this.packageName = '@astral/validations';
4
+ this.error = (message, err) => {
5
+ console.error(`${this.packageName}: ${message}`, err);
6
+ };
7
+ }
8
+ }
9
+ export const logger = new Logger();
@@ -0,0 +1,8 @@
1
+ import { AsyncValidationRule, ValidationRule } from '../types';
2
+ import { ValidationResult } from '../../types';
3
+ import { ValidationContext } from '../../context';
4
+ /**
5
+ * Позволяет рекурсивно вызывать асинхронные правила. Rule может возвращать другой rule
6
+ * Если один из rule выбросит exception, то функция его обработает и вернет дефолтную ошибку
7
+ */
8
+ export declare const callAsyncRule: <TValue, TLastSchemaValues extends Record<string, unknown>>(rule: ValidationRule<TValue, TLastSchemaValues> | AsyncValidationRule<TValue, TLastSchemaValues>, value: TValue, ctx: ValidationContext<TLastSchemaValues>) => ValidationResult | Promise<ValidationResult>;
@@ -0,0 +1,25 @@
1
+ import { REJECT_PROMISE_ERROR_INFO } from '../../errors';
2
+ import { logger } from '../../logger';
3
+ /**
4
+ * Позволяет рекурсивно вызывать асинхронные правила. Rule может возвращать другой rule
5
+ * Если один из rule выбросит exception, то функция его обработает и вернет дефолтную ошибку
6
+ */
7
+ export const callAsyncRule = (rule, value, ctx) => {
8
+ const ruleResult = rule(value, ctx);
9
+ if (ruleResult && 'then' in ruleResult) {
10
+ return ruleResult
11
+ .then((result) => {
12
+ if (typeof result === 'function') {
13
+ return callAsyncRule(result, value, ctx);
14
+ }
15
+ return result;
16
+ })
17
+ .catch((err) => {
18
+ logger.error('Ошибка при выполнении асинхронного правила', err);
19
+ return ctx.createError(REJECT_PROMISE_ERROR_INFO);
20
+ });
21
+ }
22
+ return typeof ruleResult === 'function'
23
+ ? callAsyncRule(ruleResult, value, ctx)
24
+ : ruleResult;
25
+ };
@@ -0,0 +1 @@
1
+ export * from './callAsyncRule';
@@ -0,0 +1 @@
1
+ export * from './callAsyncRule';
@@ -2,3 +2,4 @@ export * from './createRule';
2
2
  export * from './types';
3
3
  export * from './required';
4
4
  export * from './callRule';
5
+ export * from './callAsyncRule';
@@ -2,3 +2,4 @@ export * from './createRule';
2
2
  export * from './types';
3
3
  export * from './required';
4
4
  export * from './callRule';
5
+ export * from './callAsyncRule';
@@ -4,10 +4,18 @@ import { ValidationResult } from '../types';
4
4
  * @description Самостоятельное правило для валидации. Может использоваться вне guard'ов
5
5
  */
6
6
  export type IndependentValidationRule<TValue, TLastSchemaValues extends Record<string, unknown>> = (value: TValue, ctx?: ValidationContext<TLastSchemaValues>) => ValidationResult;
7
+ /**
8
+ * @description Самостоятельное асинхронное правило для валидации. Может использоваться вне guard'ов
9
+ */
10
+ export type AsyncIndependentValidationRule<TValue, TLastSchemaValues extends Record<string, unknown>> = (value: TValue, ctx?: ValidationContext<TLastSchemaValues>) => Promise<ValidationResult>;
7
11
  /**
8
12
  * @description Правило для валидации, работающее исключительно с guard'ами
9
13
  */
10
14
  export type ValidationRule<TValue, TLastSchemaValues extends Record<string, unknown> = {}> = (value: TValue, ctx: ValidationContext<TLastSchemaValues>) => ValidationResult | ValidationRule<TValue, TLastSchemaValues>;
15
+ /**
16
+ * @description Асинхронное правило для валидации, работающее исключительно с guard'ами
17
+ */
18
+ export type AsyncValidationRule<TValue, TLastSchemaValues extends Record<string, unknown> = {}> = (value: TValue, ctx: ValidationContext<TLastSchemaValues>) => Promise<ValidationResult | AsyncValidationRule<TValue, TLastSchemaValues> | ValidationRule<TValue, TLastSchemaValues>>;
11
19
  /**
12
20
  * @description Композиционное правило валидации, умеющее работать с любыми значениями.
13
21
  * В основном используется для композиционных правил, которые принимают rule, умеющие валидировать разные значения (optional, transform...)
package/date/date.d.ts CHANGED
@@ -15,12 +15,5 @@ type AdditionalDefOptions = {
15
15
  * validate(new Date('22.22.2022'));
16
16
  * ```
17
17
  */
18
- export declare const date: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<Date, TLastSchemaValues>[]) => {
19
- (value: unknown, prevCtx?: import("../core").ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
20
- define(overridesDefOptions: Partial<AdditionalDefOptions> & {
21
- requiredErrorMessage?: string | undefined;
22
- typeErrorMessage?: string | undefined;
23
- isOptional?: boolean | undefined;
24
- }): any;
25
- };
18
+ export declare const date: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<Date, TLastSchemaValues>[]) => import("../core").Guard<TLastSchemaValues, AdditionalDefOptions>;
26
19
  export {};
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { object, OBJECT_TYPE_ERROR_INFO, type Schema, type SchemaValue, type ObjectGuard, } from './object';
1
+ export { object, objectAsync, OBJECT_TYPE_ERROR_INFO, type Schema, type SchemaValue, type ObjectGuard, type ObjectAsyncGuard, } from './object';
2
2
  export { optional } from './optional';
3
- export { string, STRING_TYPE_ERROR_INFO } from './string';
3
+ export { string, STRING_TYPE_ERROR_INFO, stringAsync } from './string';
4
4
  export { date, INVALID_DATE_ERROR_INFO, DATE_TYPE_ERROR_INFO } from './date';
5
5
  export { number, NAN_NUMBER_ERROR_INFO, NUMBER_TYPE_ERROR_INFO, INFINITY_NUMBER_ERROR_INFO, } from './number';
6
6
  export { boolean, BOOLEAN_TYPE_ERROR_INFO } from './boolean';
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { object, OBJECT_TYPE_ERROR_INFO, } from './object';
1
+ export { object, objectAsync, OBJECT_TYPE_ERROR_INFO, } from './object';
2
2
  export { optional } from './optional';
3
- export { string, STRING_TYPE_ERROR_INFO } from './string';
3
+ export { string, STRING_TYPE_ERROR_INFO, stringAsync } from './string';
4
4
  export { date, INVALID_DATE_ERROR_INFO, DATE_TYPE_ERROR_INFO } from './date';
5
5
  export { number, NAN_NUMBER_ERROR_INFO, NUMBER_TYPE_ERROR_INFO, INFINITY_NUMBER_ERROR_INFO, } from './number';
6
6
  export { boolean, BOOLEAN_TYPE_ERROR_INFO } from './boolean';
@@ -15,12 +15,5 @@ type AdditionalDefOptions = {
15
15
  * validate(24);
16
16
  * ```
17
17
  */
18
- export declare const number: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<number, TLastSchemaValues>[]) => {
19
- (value: unknown, prevCtx?: import("../core").ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
20
- define(overridesDefOptions: Partial<AdditionalDefOptions> & {
21
- requiredErrorMessage?: string | undefined;
22
- typeErrorMessage?: string | undefined;
23
- isOptional?: boolean | undefined;
24
- }): any;
25
- };
18
+ export declare const number: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<number, TLastSchemaValues>[]) => import("../core").Guard<TLastSchemaValues, AdditionalDefOptions>;
26
19
  export {};
package/object/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './object';
2
2
  export * from './constants';
3
+ export * from './objectAsync';
package/object/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './object';
2
2
  export * from './constants';
3
+ export * from './objectAsync';
@@ -44,13 +44,6 @@ export type Schema<TValue extends Record<string, unknown>> = Record<keyof TValue
44
44
  * });
45
45
  * ```
46
46
  */
47
- export declare const object: <TValue extends Record<string, unknown>, TLastSchemaValues extends Record<string, unknown> = {}>(schema: Schema<TValue>) => {
48
- (value: unknown, prevCtx?: ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
49
- define(overridesDefOptions: Partial<AdditionalDefOptions> & {
50
- requiredErrorMessage?: string | undefined;
51
- typeErrorMessage?: string | undefined;
52
- isOptional?: boolean | undefined;
53
- }): any;
54
- };
47
+ export declare const object: <TValue extends Record<string, unknown>, TLastSchemaValues extends Record<string, unknown> = {}>(schema: Schema<TValue>) => Guard<TLastSchemaValues, AdditionalDefOptions>;
55
48
  export type ObjectGuard<TValue extends Record<string, unknown>> = ReturnType<typeof object<TValue>>;
56
49
  export {};
@@ -0,0 +1 @@
1
+ export * from './objectAsync';
@@ -0,0 +1 @@
1
+ export * from './objectAsync';
@@ -0,0 +1,61 @@
1
+ import { AsyncGuard, AsyncValidationRule, Guard, ValidationContext, ValidationRule } from '../../core';
2
+ /**
3
+ * @description Специальный итерфейс Guard для object. В данном интерфейсе ctx required
4
+ * Переопределение необходимо для того, чтобы ts показывал, что ctx required в кастомных правилах
5
+ */
6
+ interface ObjectPropGuard<TLastSchemaValues extends Record<string, unknown>> {
7
+ (value: Parameters<Guard<TLastSchemaValues>>[0], ctx: ValidationContext<TLastSchemaValues>): ReturnType<Guard<TLastSchemaValues>>;
8
+ define: Guard<TLastSchemaValues>['define'];
9
+ }
10
+ interface AsyncObjectPropGuard<TLastSchemaValues extends Record<string, unknown>> {
11
+ (value: Parameters<Guard<TLastSchemaValues>>[0], ctx: ValidationContext<TLastSchemaValues>): ReturnType<AsyncGuard<TLastSchemaValues>>;
12
+ define: AsyncGuard<TLastSchemaValues>['define'];
13
+ }
14
+ type AdditionalDefOptions = {
15
+ /**
16
+ * @description Делает все свойства объекта partial
17
+ */
18
+ isPartial?: boolean;
19
+ };
20
+ /**
21
+ * @description Возможные значения, принимаемые схемой
22
+ */
23
+ export type AsyncSchemaValue<TValue extends Record<string, unknown>> = ObjectPropGuard<TValue> | AsyncObjectPropGuard<TValue> | ValidationRule<unknown, TValue> | AsyncValidationRule<unknown, TValue>;
24
+ /**
25
+ * @description Схема правил валдиации для объекта
26
+ */
27
+ export type AsyncSchema<TValue extends Record<string, unknown>> = Record<keyof TValue, AsyncSchemaValue<TValue>>;
28
+ /**
29
+ * @description Guard для объекта, который поддерживает асинхронную валидацию
30
+ * @example
31
+ * ```ts
32
+ * type Values = {
33
+ * name: string;
34
+ * age?: number;
35
+ * info: { surname: string };
36
+ * };
37
+ *
38
+ * const values: Values = { name: 'Vasya', info: { surname: 'Vasin' } };
39
+ *
40
+ * const validateObject = objectAsync<Values>({
41
+ * name: string(min(2), async (value, ctx) => {
42
+ * const result = await validateName(value);
43
+ *
44
+ * return result.isInvalid
45
+ * ? ctx.createError({
46
+ * message: 'Имя занято',
47
+ * code: 'name-is-not-available',
48
+ * })
49
+ * : undefined;
50
+ * }),
51
+ * age: optional(number()),
52
+ * info: object<Values['info']>({ surname: string(min(2)) }),
53
+ * customField: (value, ctx) => {
54
+ * return ctx.createError({ message: 'error', code: 'custom error' });
55
+ * },
56
+ * });
57
+ * ```
58
+ */
59
+ export declare const objectAsync: <TValue extends Record<string, unknown>, TLastSchemaValues extends Record<string, unknown> = {}>(schema: AsyncSchema<TValue>) => AsyncGuard<TLastSchemaValues, AdditionalDefOptions>;
60
+ export type ObjectAsyncGuard<TValue extends Record<string, unknown>> = ReturnType<typeof objectAsync<TValue>>;
61
+ export {};
@@ -0,0 +1,71 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import isPlainObject from 'is-plain-obj';
11
+ import { callAsyncRule as callAsyncRecursiveRule, createContext, createErrorMap, createGuard, } from '../../core';
12
+ import { optional } from '../../optional';
13
+ import { isEmptyErrors } from '../isEmptyErrors';
14
+ import { OBJECT_TYPE_ERROR_INFO } from '../constants';
15
+ // TODO: необходимо реализовать переиспользование логики между object и objectAsync
16
+ /**
17
+ * @description Guard для объекта, который поддерживает асинхронную валидацию
18
+ * @example
19
+ * ```ts
20
+ * type Values = {
21
+ * name: string;
22
+ * age?: number;
23
+ * info: { surname: string };
24
+ * };
25
+ *
26
+ * const values: Values = { name: 'Vasya', info: { surname: 'Vasin' } };
27
+ *
28
+ * const validateObject = objectAsync<Values>({
29
+ * name: string(min(2), async (value, ctx) => {
30
+ * const result = await validateName(value);
31
+ *
32
+ * return result.isInvalid
33
+ * ? ctx.createError({
34
+ * message: 'Имя занято',
35
+ * code: 'name-is-not-available',
36
+ * })
37
+ * : undefined;
38
+ * }),
39
+ * age: optional(number()),
40
+ * info: object<Values['info']>({ surname: string(min(2)) }),
41
+ * customField: (value, ctx) => {
42
+ * return ctx.createError({ message: 'error', code: 'custom error' });
43
+ * },
44
+ * });
45
+ * ```
46
+ */
47
+ export const objectAsync = (schema) => createGuard((value, ctx, { typeErrorMessage, isPartial }) => __awaiter(void 0, void 0, void 0, function* () {
48
+ const context = createContext(ctx, value, value);
49
+ if (!isPlainObject(value)) {
50
+ return context.createError(Object.assign(Object.assign({}, OBJECT_TYPE_ERROR_INFO), { message: typeErrorMessage || OBJECT_TYPE_ERROR_INFO.message }));
51
+ }
52
+ const generateErrorMap = () => __awaiter(void 0, void 0, void 0, function* () {
53
+ const schemaEntries = Object.entries(schema);
54
+ const isOptional = context.global.overrides.objectIsPartial || isPartial;
55
+ const results = yield Promise.all(schemaEntries.map(([key, rule]) => {
56
+ const isGuard = 'define' in rule;
57
+ const callRule = isGuard && isOptional ? optional(rule) : rule;
58
+ return callAsyncRecursiveRule(callRule, value[key], context);
59
+ }));
60
+ return results.reduce((errorMap, validationResult, index) => {
61
+ const [key] = schemaEntries[index];
62
+ errorMap[key] = validationResult;
63
+ return errorMap;
64
+ }, {});
65
+ });
66
+ const errorMap = yield generateErrorMap();
67
+ if (!isEmptyErrors(errorMap)) {
68
+ return createErrorMap(errorMap);
69
+ }
70
+ return undefined;
71
+ }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astral/validations",
3
- "version": "4.6.1",
3
+ "version": "4.7.0",
4
4
  "browser": "./index.js",
5
5
  "main": "./index.js",
6
6
  "dependencies": {
@@ -4,13 +4,6 @@ import { object } from '../object';
4
4
  * @param objectGuard
5
5
  * @example partial(object({ name: string() }))
6
6
  */
7
- export declare const partial: (objectGuard: ReturnType<typeof object>) => {
8
- (value: unknown, prevCtx?: import("../core").ValidationContext<Record<string, unknown>> | undefined): import("../core").ValidationResult;
9
- define(overridesDefOptions: Partial<{
10
- isPartial?: boolean | undefined;
11
- }> & {
12
- requiredErrorMessage?: string | undefined;
13
- typeErrorMessage?: string | undefined;
14
- isOptional?: boolean | undefined;
15
- }): any;
16
- };
7
+ export declare const partial: (objectGuard: ReturnType<typeof object>) => import("../core").Guard<Record<string, unknown>, {
8
+ isPartial?: boolean | undefined;
9
+ }>;
package/string/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './string';
2
+ export * from './stringAsync';
2
3
  export * from './constants';
package/string/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './string';
2
+ export * from './stringAsync';
2
3
  export * from './constants';
@@ -1,9 +1,2 @@
1
1
  import { ValidationRule } from '../core';
2
- export declare const string: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<string, TLastSchemaValues>[]) => {
3
- (value: unknown, prevCtx?: import("../core").ValidationContext<TLastSchemaValues> | undefined): import("../core").ValidationResult;
4
- define(overridesDefOptions: Partial<{}> & {
5
- requiredErrorMessage?: string | undefined;
6
- typeErrorMessage?: string | undefined;
7
- isOptional?: boolean | undefined;
8
- }): any;
9
- };
2
+ export declare const string: <TLastSchemaValues extends Record<string, unknown>>(...rules: ValidationRule<string, TLastSchemaValues>[]) => import("../core").Guard<TLastSchemaValues, {}>;
package/string/string.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { compose, createGuard } from '../core';
2
2
  import { STRING_TYPE_ERROR_INFO } from './constants';
3
+ import { isString } from './utils';
3
4
  export const string = (...rules) => createGuard((value, ctx, { typeErrorMessage }) => {
4
- if (typeof value !== 'string') {
5
+ if (!isString(value)) {
5
6
  return ctx.createError(Object.assign(Object.assign({}, STRING_TYPE_ERROR_INFO), { message: typeErrorMessage || STRING_TYPE_ERROR_INFO.message }));
6
7
  }
7
8
  return compose(...rules)(value, ctx);
@@ -0,0 +1 @@
1
+ export * from './stringAsync';
@@ -0,0 +1 @@
1
+ export * from './stringAsync';
@@ -0,0 +1,6 @@
1
+ import { AsyncValidationRule, ValidationRule } from '../../core';
2
+ /**
3
+ * Позволяет использовать для валидации асинхронные правила
4
+ * @example stringAsync(async () => undefined)
5
+ */
6
+ export declare const stringAsync: <TLastSchemaValues extends Record<string, unknown>>(...rules: (ValidationRule<string, TLastSchemaValues> | AsyncValidationRule<string, TLastSchemaValues>)[]) => import("../../core").AsyncGuard<TLastSchemaValues, {}>;
@@ -0,0 +1,23 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { composeAsync, createGuard, } from '../../core';
11
+ import { isString } from '../utils';
12
+ import { STRING_TYPE_ERROR_INFO } from '../constants';
13
+ // TODO: необходимо реализовать переиспользование логики между string и stringAsync
14
+ /**
15
+ * Позволяет использовать для валидации асинхронные правила
16
+ * @example stringAsync(async () => undefined)
17
+ */
18
+ export const stringAsync = (...rules) => createGuard((value, ctx, { typeErrorMessage }) => __awaiter(void 0, void 0, void 0, function* () {
19
+ if (!isString(value)) {
20
+ return ctx.createError(Object.assign(Object.assign({}, STRING_TYPE_ERROR_INFO), { message: typeErrorMessage || STRING_TYPE_ERROR_INFO.message }));
21
+ }
22
+ return composeAsync(...rules)(value, ctx);
23
+ }));
@@ -0,0 +1 @@
1
+ export * from './isString';
@@ -0,0 +1 @@
1
+ export * from './isString';
@@ -0,0 +1 @@
1
+ export * from './isString';
@@ -0,0 +1 @@
1
+ export * from './isString';
@@ -0,0 +1 @@
1
+ export declare const isString: (value: unknown) => value is string;
@@ -0,0 +1 @@
1
+ export const isString = (value) => typeof value === 'string';