@pogodisco/val 0.0.1

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 (39) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +3 -0
  3. package/dist/rules/array.d.ts +6 -0
  4. package/dist/rules/array.js +28 -0
  5. package/dist/rules/boolean.d.ts +2 -0
  6. package/dist/rules/boolean.js +10 -0
  7. package/dist/rules/date.d.ts +7 -0
  8. package/dist/rules/date.js +20 -0
  9. package/dist/rules/helpers.d.ts +6 -0
  10. package/dist/rules/helpers.js +26 -0
  11. package/dist/rules/index.d.ts +7 -0
  12. package/dist/rules/index.js +7 -0
  13. package/dist/rules/number.d.ts +11 -0
  14. package/dist/rules/number.js +27 -0
  15. package/dist/rules/object.d.ts +4 -0
  16. package/dist/rules/object.js +4 -0
  17. package/dist/rules/string.d.ts +12 -0
  18. package/dist/rules/string.js +21 -0
  19. package/dist/types/index.d.ts +16 -0
  20. package/dist/types/index.js +1 -0
  21. package/dist/utils/core-rules.d.ts +68 -0
  22. package/dist/utils/core-rules.js +67 -0
  23. package/dist/utils/flatten-rules.d.ts +2 -0
  24. package/dist/utils/flatten-rules.js +24 -0
  25. package/dist/utils/index.d.ts +8 -0
  26. package/dist/utils/index.js +8 -0
  27. package/dist/utils/schema.d.ts +3 -0
  28. package/dist/utils/schema.js +6 -0
  29. package/dist/utils/validate.d.ts +5 -0
  30. package/dist/utils/validate.js +28 -0
  31. package/dist/utils/validation-rule-builder.d.ts +13 -0
  32. package/dist/utils/validation-rule-builder.js +27 -0
  33. package/dist/utils/validation-rule.d.ts +14 -0
  34. package/dist/utils/validation-rule.js +14 -0
  35. package/dist/utils/wrap-async-rule.d.ts +4 -0
  36. package/dist/utils/wrap-async-rule.js +30 -0
  37. package/dist/utils/wrap-sync-rule.d.ts +2 -0
  38. package/dist/utils/wrap-sync-rule.js +21 -0
  39. package/package.json +37 -0
@@ -0,0 +1,3 @@
1
+ export * from "./rules";
2
+ export * from "./utils";
3
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./rules";
2
+ export * from "./utils";
3
+ export * from "./types";
@@ -0,0 +1,6 @@
1
+ export declare const isOneOf: <T>(allowedValues: readonly T[], value: unknown) => value is T;
2
+ export declare const arrayMax: (arr: any[], max: number) => boolean;
3
+ export declare const arrayMin: (arr: any[], min: number) => boolean;
4
+ export declare const allEqual: (values: readonly any[]) => boolean;
5
+ export declare const isArray: (value: any) => value is any[];
6
+ export declare const each: (values: readonly any[], predicate: (v: unknown) => boolean) => boolean;
@@ -0,0 +1,28 @@
1
+ export const isOneOf = (allowedValues, value) => {
2
+ return allowedValues.includes(value);
3
+ };
4
+ export const arrayMax = (arr, max) => {
5
+ if (!Array.isArray(arr))
6
+ return false;
7
+ return arr.length <= max;
8
+ };
9
+ export const arrayMin = (arr, min) => {
10
+ if (!Array.isArray(arr))
11
+ return false;
12
+ return arr.length >= min;
13
+ };
14
+ export const allEqual = (values) => {
15
+ if (values.length === 0)
16
+ return true;
17
+ const firstType = typeof values[0];
18
+ const firstValue = values[0];
19
+ if (!values.every((v) => typeof v === firstType))
20
+ return false;
21
+ return values.every((v) => v === firstValue);
22
+ };
23
+ export const isArray = (value) => Array.isArray(value);
24
+ export const each = (values, predicate) => {
25
+ if (!Array.isArray(values))
26
+ return false;
27
+ return values.every(predicate);
28
+ };
@@ -0,0 +1,2 @@
1
+ export declare const isTrue: (v: boolean) => boolean;
2
+ export declare const isFalse: (v: boolean) => boolean;
@@ -0,0 +1,10 @@
1
+ export const isTrue = (v) => {
2
+ if (typeof v !== "boolean")
3
+ return false;
4
+ return v === true;
5
+ };
6
+ export const isFalse = (v) => {
7
+ if (typeof v !== "boolean")
8
+ return false;
9
+ return v === false;
10
+ };
@@ -0,0 +1,7 @@
1
+ export declare const isDate: (value: any) => boolean;
2
+ export declare const isBefore: (date: Date | string, value: any) => boolean;
3
+ export declare const isAfter: (date: Date | string, value: any) => boolean;
4
+ export declare const isBetween: (start: Date, end: Date, value: any) => boolean;
5
+ export declare const isToday: () => (value: any) => boolean;
6
+ export declare const isFutureDate: (value: any) => boolean;
7
+ export declare const isPastDate: (value: any) => boolean;
@@ -0,0 +1,20 @@
1
+ export const isDate = (value) => value instanceof Date && !isNaN(value.getTime());
2
+ export const isBefore = (date, value) => {
3
+ const d = new Date(date);
4
+ return value instanceof Date && value < d;
5
+ };
6
+ export const isAfter = (date, value) => {
7
+ const d = new Date(date);
8
+ return value instanceof Date && value > d;
9
+ };
10
+ export const isBetween = (start, end, value) => value instanceof Date && value >= start && value <= end;
11
+ export const isToday = () => (value) => {
12
+ if (!(value instanceof Date))
13
+ return false;
14
+ const today = new Date();
15
+ return (value.getFullYear() === today.getFullYear() &&
16
+ value.getMonth() === today.getMonth() &&
17
+ value.getDate() === today.getDate());
18
+ };
19
+ export const isFutureDate = (value) => value instanceof Date && value > new Date();
20
+ export const isPastDate = (value) => value instanceof Date && value < new Date();
@@ -0,0 +1,6 @@
1
+ export declare const requiredUnless: (conditions: boolean[], v: any) => boolean;
2
+ export declare const requiredIf: (conditions: boolean[], v: any) => boolean;
3
+ export declare const requiredIfElseEmpty: (conditions: boolean[], v: any) => boolean;
4
+ export declare function mustBeEmptyIf(conditions: boolean[], value: any): boolean;
5
+ export declare const isOptional: (v: any) => boolean;
6
+ export declare const isNotEmpty: (v: any) => boolean;
@@ -0,0 +1,26 @@
1
+ export const requiredUnless = (conditions, v) => {
2
+ return conditions.every(Boolean)
3
+ ? true
4
+ : v !== undefined && v !== null && v !== "";
5
+ };
6
+ export const requiredIf = (conditions, v) => {
7
+ return conditions.every(Boolean)
8
+ ? v !== undefined && v !== null && v !== ""
9
+ : true;
10
+ };
11
+ export const requiredIfElseEmpty = (conditions, v) => {
12
+ return conditions.some(Boolean)
13
+ ? v !== undefined && v !== null && v !== ""
14
+ : v === undefined || v === null || v === "";
15
+ };
16
+ export function mustBeEmptyIf(conditions, value) {
17
+ return conditions.some(Boolean) ? value == null || value === "" : true;
18
+ }
19
+ export const isOptional = (v) => {
20
+ return v === undefined || v === null || v === "";
21
+ };
22
+ export const isNotEmpty = (v) => {
23
+ if (v === null || v === undefined || v === "")
24
+ return false;
25
+ return true;
26
+ };
@@ -0,0 +1,7 @@
1
+ export * from "./number";
2
+ export * from "./array";
3
+ export * from "./string";
4
+ export * from "./boolean";
5
+ export * from "./helpers";
6
+ export * from "./date";
7
+ export * from "./object";
@@ -0,0 +1,7 @@
1
+ export * from "./number";
2
+ export * from "./array";
3
+ export * from "./string";
4
+ export * from "./boolean";
5
+ export * from "./helpers";
6
+ export * from "./date";
7
+ export * from "./object";
@@ -0,0 +1,11 @@
1
+ export declare const isInteger: (value: any) => boolean;
2
+ export declare const isFloat: (value: any) => boolean;
3
+ export declare const isPositive: (value: any) => boolean;
4
+ export declare const isNegative: (value: any) => boolean;
5
+ export declare const isEven: (value: any) => boolean;
6
+ export declare const isOdd: (value: any) => boolean;
7
+ export declare const isMultipleOf: (n: number, value: any) => boolean;
8
+ export declare const numberGt: (v: number, gt: number) => boolean;
9
+ export declare const numberLt: (v: number, lt: number) => boolean;
10
+ export declare const numberMax: (v: number, max: number) => boolean;
11
+ export declare const numberMin: (v: number, min: number) => boolean;
@@ -0,0 +1,27 @@
1
+ export const isInteger = (value) => typeof value === "number" && Number.isInteger(value);
2
+ export const isFloat = (value) => typeof value === "number" && !Number.isInteger(value);
3
+ export const isPositive = (value) => typeof value === "number" && value > 0;
4
+ export const isNegative = (value) => typeof value === "number" && value < 0;
5
+ export const isEven = (value) => typeof value === "number" && value % 2 === 0;
6
+ export const isOdd = (value) => typeof value === "number" && value % 2 !== 0;
7
+ export const isMultipleOf = (n, value) => typeof value === "number" && value % n === 0;
8
+ export const numberGt = (v, gt) => {
9
+ if (typeof v !== "number" || isNaN(v))
10
+ return false;
11
+ return v > gt;
12
+ };
13
+ export const numberLt = (v, lt) => {
14
+ if (typeof v !== "number" || isNaN(v))
15
+ return false;
16
+ return v < lt;
17
+ };
18
+ export const numberMax = (v, max) => {
19
+ if (typeof v !== "number" || isNaN(v))
20
+ return false;
21
+ return v <= max;
22
+ };
23
+ export const numberMin = (v, min) => {
24
+ if (typeof v !== "number" || isNaN(v))
25
+ return false;
26
+ return v >= min;
27
+ };
@@ -0,0 +1,4 @@
1
+ export declare const isObject: (value: any) => boolean;
2
+ export declare const hasKeys: (value: any, ...keys: string[]) => boolean;
3
+ export declare const maxKeys: (n: number, value: any) => boolean;
4
+ export declare const minKeys: (n: number, value: any) => boolean;
@@ -0,0 +1,4 @@
1
+ export const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
2
+ export const hasKeys = (value, ...keys) => isObject(value) && keys.every((key) => key in value);
3
+ export const maxKeys = (n, value) => isObject(value) && Object.keys(value).length <= n;
4
+ export const minKeys = (n, value) => isObject(value) && Object.keys(value).length >= n;
@@ -0,0 +1,12 @@
1
+ export declare const charsMin: (v: string, min: number) => boolean;
2
+ export declare const contains: (substr: string, value: any) => boolean;
3
+ export declare const startsWith: (substr: string, value: any) => boolean;
4
+ export declare const endsWith: (substr: string, value: any) => boolean;
5
+ export declare const hasLength: (value: any, min: number, max?: number) => boolean;
6
+ export declare const isAlpha: (value: any) => boolean;
7
+ export declare const isAlphanumeric: (value: any) => boolean;
8
+ export declare const isEmail: (str: string) => boolean;
9
+ export declare const isLowerCase: (value: any) => boolean;
10
+ export declare const isUpperCase: (value: any) => boolean;
11
+ export declare const matchesRegex: (regex: RegExp, value: any) => boolean;
12
+ export declare const isSlug: (value: any) => boolean;
@@ -0,0 +1,21 @@
1
+ export const charsMin = (v, min) => {
2
+ if (!v || typeof v !== "string" || v.length < min) {
3
+ return false;
4
+ }
5
+ return true;
6
+ };
7
+ export const contains = (substr, value) => typeof value === "string" && value.includes(substr);
8
+ export const startsWith = (substr, value) => typeof value === "string" && value.startsWith(substr);
9
+ export const endsWith = (substr, value) => typeof value === "string" && value.endsWith(substr);
10
+ export const hasLength = (value, min, max) => typeof value === "string" &&
11
+ value.length >= min &&
12
+ (max === undefined || value.length <= max);
13
+ export const isAlpha = (value) => typeof value === "string" && /^[a-z]+$/i.test(value);
14
+ export const isAlphanumeric = (value) => typeof value === "string" && /^[a-z0-9]+$/i.test(value);
15
+ export const isEmail = (str) => {
16
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
17
+ };
18
+ export const isLowerCase = (value) => typeof value === "string" && value === value.toLowerCase();
19
+ export const isUpperCase = (value) => typeof value === "string" && value === value.toUpperCase();
20
+ export const matchesRegex = (regex, value) => typeof value === "string" && regex.test(value);
21
+ export const isSlug = (value) => typeof value === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
@@ -0,0 +1,16 @@
1
+ import type { ValidationRule } from "../utils/validation-rule";
2
+ export type ValidationResult = {
3
+ ok: boolean;
4
+ errors: Record<string, any>;
5
+ };
6
+ export type RuleResult = boolean | {
7
+ ok: boolean;
8
+ } | Promise<boolean> | Promise<{
9
+ ok: boolean;
10
+ }>;
11
+ export type RuleBuilder = {
12
+ errors(errors: ValidationRule["errors"]): RuleBuilder;
13
+ bail(bail?: boolean): RuleBuilder;
14
+ runIf(fn: () => boolean | Promise<boolean>): RuleBuilder;
15
+ build(): ValidationRule;
16
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ interface Validator {
3
+ format: {
4
+ date: {
5
+ isDate: (value: any) => ValidationRuleBuilder;
6
+ isBefore: (date: string | Date, value: any) => ValidationRuleBuilder;
7
+ isAfter: (date: string | Date, value: any) => ValidationRuleBuilder;
8
+ isBetween: (start: Date, end: Date, value: any) => ValidationRuleBuilder;
9
+ isFuture: (date: string | Date, value: any) => ValidationRuleBuilder;
10
+ isPast: (date: string | Date, value: any) => ValidationRuleBuilder;
11
+ };
12
+ string: {
13
+ min: (v: string, min: number) => ValidationRuleBuilder;
14
+ email: (value: any) => ValidationRuleBuilder;
15
+ matchesRegex: (regex: RegExp, value: any) => ValidationRuleBuilder;
16
+ startsWith: (substr: string, value: any) => ValidationRuleBuilder;
17
+ endsWith: (substr: string, value: any) => ValidationRuleBuilder;
18
+ contains: (substr: string, value: any) => ValidationRuleBuilder;
19
+ isLowerCase: (value: any) => ValidationRuleBuilder;
20
+ isUpperCase: (value: any) => ValidationRuleBuilder;
21
+ hasLength: (value: any, min: number, max?: number | undefined) => ValidationRuleBuilder;
22
+ isAlpha: (value: any) => ValidationRuleBuilder;
23
+ isAlphanumeric: (value: any) => ValidationRuleBuilder;
24
+ isSlug: (value: any) => ValidationRuleBuilder;
25
+ };
26
+ boolean: {
27
+ isTrue: (value: any) => ValidationRuleBuilder;
28
+ isFalse: (value: any) => ValidationRuleBuilder;
29
+ };
30
+ number: {
31
+ min: (v: number, min: number) => ValidationRuleBuilder;
32
+ max: (v: number, max: number) => ValidationRuleBuilder;
33
+ gt: (v: number, gt: number) => ValidationRuleBuilder;
34
+ lt: (v: number, lt: number) => ValidationRuleBuilder;
35
+ isOdd: (value: any) => ValidationRuleBuilder;
36
+ isEven: (value: any) => ValidationRuleBuilder;
37
+ isFloat: (value: any) => ValidationRuleBuilder;
38
+ isInteger: (value: any) => ValidationRuleBuilder;
39
+ isPositive: (value: any) => ValidationRuleBuilder;
40
+ isMultipleOf: (n: number, value: any) => ValidationRuleBuilder;
41
+ isNegative: (value: any) => ValidationRuleBuilder;
42
+ };
43
+ array: {
44
+ isArray: (value: any) => ValidationRuleBuilder;
45
+ equal: (values: readonly any[]) => ValidationRuleBuilder;
46
+ min: (arr: any[], min: number) => ValidationRuleBuilder;
47
+ max: (arr: any[], max: number) => ValidationRuleBuilder;
48
+ each: (arr: any[], predicate: (v: any) => boolean) => ValidationRuleBuilder;
49
+ };
50
+ object: {
51
+ isObject: (value: any) => ValidationRuleBuilder;
52
+ hasKeys: (value: any, ...keys: string[]) => ValidationRuleBuilder;
53
+ maxKeys: (n: number, value: any) => ValidationRuleBuilder;
54
+ minKeys: (n: number, value: any) => ValidationRuleBuilder;
55
+ };
56
+ };
57
+ optional: (value: any) => ValidationRuleBuilder;
58
+ required: {
59
+ unless: (conditions: boolean[], v: any) => ValidationRuleBuilder;
60
+ _if: (conditions: boolean[], v: any) => ValidationRuleBuilder;
61
+ _ifElseEmpty: (conditions: boolean[], v: any) => ValidationRuleBuilder;
62
+ from: (allowedValues: readonly unknown[], value: unknown) => ValidationRuleBuilder;
63
+ emptyIf: (conditions: boolean[], v: any) => ValidationRuleBuilder;
64
+ strict: (value: any) => ValidationRuleBuilder;
65
+ };
66
+ }
67
+ export declare const v: Validator;
68
+ export {};
@@ -0,0 +1,67 @@
1
+ import { allEqual, each, arrayMax, arrayMin, charsMin, isEmail, isNotEmpty, isOneOf, mustBeEmptyIf, numberMax, numberMin, requiredIfElseEmpty, requiredIf, requiredUnless, numberGt, numberLt, isOptional, isTrue, isFalse, matchesRegex, isAlphanumeric, isAlpha, isSlug, hasLength, startsWith, endsWith, contains, isLowerCase, isUpperCase, isOdd, isEven, isFloat, isInteger, isPositive, isMultipleOf, isNegative, isDate, isBefore, isAfter, isBetween, isFutureDate, isPastDate, isObject, isArray, hasKeys, maxKeys, minKeys, } from "../rules";
2
+ import { wrapSyncRule } from "./wrap-sync-rule";
3
+ export const v = {
4
+ format: {
5
+ date: {
6
+ isDate: wrapSyncRule(isDate),
7
+ isBefore: wrapSyncRule(isBefore),
8
+ isAfter: wrapSyncRule(isAfter),
9
+ isBetween: wrapSyncRule(isBetween),
10
+ isFuture: wrapSyncRule(isFutureDate),
11
+ isPast: wrapSyncRule(isPastDate),
12
+ },
13
+ string: {
14
+ min: wrapSyncRule(charsMin),
15
+ email: wrapSyncRule(isEmail),
16
+ matchesRegex: wrapSyncRule(matchesRegex),
17
+ startsWith: wrapSyncRule(startsWith),
18
+ endsWith: wrapSyncRule(endsWith),
19
+ contains: wrapSyncRule(contains),
20
+ isLowerCase: wrapSyncRule(isLowerCase),
21
+ isUpperCase: wrapSyncRule(isUpperCase),
22
+ hasLength: wrapSyncRule(hasLength),
23
+ isAlpha: wrapSyncRule(isAlpha),
24
+ isAlphanumeric: wrapSyncRule(isAlphanumeric),
25
+ isSlug: wrapSyncRule(isSlug),
26
+ },
27
+ boolean: {
28
+ isTrue: wrapSyncRule(isTrue),
29
+ isFalse: wrapSyncRule(isFalse),
30
+ },
31
+ number: {
32
+ min: wrapSyncRule(numberMin),
33
+ max: wrapSyncRule(numberMax),
34
+ gt: wrapSyncRule(numberGt),
35
+ lt: wrapSyncRule(numberLt),
36
+ isOdd: wrapSyncRule(isOdd),
37
+ isEven: wrapSyncRule(isEven),
38
+ isFloat: wrapSyncRule(isFloat),
39
+ isInteger: wrapSyncRule(isInteger),
40
+ isPositive: wrapSyncRule(isPositive),
41
+ isMultipleOf: wrapSyncRule(isMultipleOf),
42
+ isNegative: wrapSyncRule(isNegative),
43
+ },
44
+ array: {
45
+ isArray: wrapSyncRule(isArray),
46
+ equal: wrapSyncRule(allEqual),
47
+ min: wrapSyncRule(arrayMin),
48
+ max: wrapSyncRule(arrayMax),
49
+ each: wrapSyncRule(each),
50
+ },
51
+ object: {
52
+ isObject: wrapSyncRule(isObject),
53
+ hasKeys: wrapSyncRule(hasKeys),
54
+ maxKeys: wrapSyncRule(maxKeys),
55
+ minKeys: wrapSyncRule(minKeys),
56
+ },
57
+ },
58
+ optional: wrapSyncRule(isOptional),
59
+ required: {
60
+ unless: wrapSyncRule(requiredUnless),
61
+ _if: wrapSyncRule(requiredIf),
62
+ _ifElseEmpty: wrapSyncRule(requiredIfElseEmpty),
63
+ from: wrapSyncRule(isOneOf),
64
+ emptyIf: wrapSyncRule(mustBeEmptyIf),
65
+ strict: wrapSyncRule(isNotEmpty),
66
+ },
67
+ };
@@ -0,0 +1,2 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export declare function flattenRuleBuilders(obj: unknown): ValidationRuleBuilder[];
@@ -0,0 +1,24 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export function flattenRuleBuilders(obj) {
3
+ const result = [];
4
+ function walk(o) {
5
+ if (!o)
6
+ return;
7
+ if (Array.isArray(o)) {
8
+ for (const item of o)
9
+ walk(item);
10
+ }
11
+ else if (typeof o === "object") {
12
+ for (const value of Object.values(o)) {
13
+ if (value instanceof ValidationRuleBuilder) {
14
+ result.push(value);
15
+ }
16
+ else {
17
+ walk(value);
18
+ }
19
+ }
20
+ }
21
+ }
22
+ walk(obj);
23
+ return result;
24
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./validate";
2
+ export * from "./schema";
3
+ export * from "./core-rules";
4
+ export * from "./wrap-async-rule";
5
+ export * from "./wrap-sync-rule";
6
+ export * from "./flatten-rules";
7
+ export * from "./validation-rule";
8
+ export * from "./validation-rule-builder";
@@ -0,0 +1,8 @@
1
+ export * from "./validate";
2
+ export * from "./schema";
3
+ export * from "./core-rules";
4
+ export * from "./wrap-async-rule";
5
+ export * from "./wrap-sync-rule";
6
+ export * from "./flatten-rules";
7
+ export * from "./validation-rule";
8
+ export * from "./validation-rule-builder";
@@ -0,0 +1,3 @@
1
+ import type { RuleBuilder } from "../types";
2
+ import { ValidationRule } from "./validation-rule";
3
+ export declare function schema<Ctx>(factory: (ctx: Ctx) => RuleBuilder[]): (ctx: Ctx) => ValidationRule[];
@@ -0,0 +1,6 @@
1
+ // schema.ts
2
+ export function schema(factory) {
3
+ return (ctx) => {
4
+ return factory(ctx).map((rb) => rb.build());
5
+ };
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { ValidationRule } from "./validation-rule";
2
+ import { type TResponse } from "@pogodisco/response";
3
+ export declare function validate({ rules, }: {
4
+ rules: ValidationRule[];
5
+ }): Promise<TResponse<null>>;
@@ -0,0 +1,28 @@
1
+ import { newFailureResponse, newSuccessResponse, } from "@pogodisco/response";
2
+ export async function validate({ rules, }) {
3
+ const validationErrors = {};
4
+ for (const rule of rules) {
5
+ if (!(await rule.shouldRun()))
6
+ continue;
7
+ const result = await rule.rule();
8
+ const isAppResponse = typeof result === "object" && result !== null && "ok" in result;
9
+ const isValid = isAppResponse ? result?.ok : result;
10
+ if (!isValid) {
11
+ for (const [key, message] of Object.entries(rule.errors)) {
12
+ validationErrors[key] = [
13
+ ...(validationErrors[key] || []),
14
+ message || "",
15
+ ];
16
+ }
17
+ if (rule.bail ?? true) {
18
+ return newFailureResponse("Validation error", {
19
+ errors: validationErrors,
20
+ });
21
+ }
22
+ }
23
+ }
24
+ if (Object.keys(validationErrors).length > 0) {
25
+ return newFailureResponse("Validation error", { errors: validationErrors });
26
+ }
27
+ return newSuccessResponse(null);
28
+ }
@@ -0,0 +1,13 @@
1
+ import type { RuleResult } from "../types";
2
+ import { ValidationRule } from "./validation-rule";
3
+ export declare class ValidationRuleBuilder {
4
+ private _rule;
5
+ private _bail?;
6
+ private _errors;
7
+ private _runIf?;
8
+ constructor(rule: () => RuleResult | Promise<RuleResult>);
9
+ errors(errors: Partial<Record<string, string>>): this;
10
+ bail(bail?: boolean): this;
11
+ runIf(fn: () => boolean | Promise<boolean>): this;
12
+ build(): ValidationRule;
13
+ }
@@ -0,0 +1,27 @@
1
+ import { ValidationRule } from "./validation-rule";
2
+ export class ValidationRuleBuilder {
3
+ constructor(rule) {
4
+ this._errors = {};
5
+ this._rule = rule;
6
+ }
7
+ errors(errors) {
8
+ this._errors = errors;
9
+ return this;
10
+ }
11
+ bail(bail = true) {
12
+ this._bail = bail;
13
+ return this;
14
+ }
15
+ runIf(fn) {
16
+ this._runIf = fn;
17
+ return this;
18
+ }
19
+ build() {
20
+ return new ValidationRule({
21
+ rule: this._rule,
22
+ bail: this._bail,
23
+ errors: this._errors,
24
+ runIf: this._runIf,
25
+ });
26
+ }
27
+ }
@@ -0,0 +1,14 @@
1
+ import type { RuleResult } from "../types";
2
+ export declare class ValidationRule {
3
+ rule: () => RuleResult | Promise<RuleResult>;
4
+ bail?: boolean;
5
+ errors: Partial<Record<string, string>>;
6
+ runIf?: () => boolean | Promise<boolean>;
7
+ constructor(options: {
8
+ rule: () => RuleResult | Promise<RuleResult>;
9
+ bail?: boolean;
10
+ errors?: Partial<Record<string, string>>;
11
+ runIf?: () => boolean | Promise<boolean>;
12
+ });
13
+ shouldRun(): Promise<boolean>;
14
+ }
@@ -0,0 +1,14 @@
1
+ export class ValidationRule {
2
+ constructor(options) {
3
+ this.rule = options.rule;
4
+ this.bail = options.bail;
5
+ this.errors = options.errors ?? {};
6
+ this.runIf = options.runIf;
7
+ }
8
+ async shouldRun() {
9
+ if (!this.runIf)
10
+ return true;
11
+ const result = this.runIf();
12
+ return typeof result === "boolean" ? result : await result;
13
+ }
14
+ }
@@ -0,0 +1,4 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export declare function wrapAsyncRule<T extends any[]>(fn: (...args: T) => Promise<{
3
+ ok: boolean;
4
+ }>): (...args: T) => ValidationRuleBuilder;
@@ -0,0 +1,30 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export function wrapAsyncRule(fn) {
3
+ return (...args) => {
4
+ const ruleFn = async () => {
5
+ const result = await fn(...args);
6
+ return result.ok;
7
+ };
8
+ const builder = new ValidationRuleBuilder(ruleFn);
9
+ const ruleName = fn.name;
10
+ if (ruleName === "isOptional") {
11
+ builder.runIf(async () => {
12
+ const result = await fn(...args);
13
+ return result.ok;
14
+ });
15
+ }
16
+ if (ruleName === "isTrue" || ruleName === "isFalse") {
17
+ builder.runIf(async () => {
18
+ const result = await fn(...args);
19
+ return result.ok;
20
+ });
21
+ }
22
+ if (["requiredIf", "requiredUnless", "requiredIfElseEmpty"].includes(ruleName)) {
23
+ const [conditions] = args;
24
+ if (Array.isArray(conditions)) {
25
+ builder.runIf(async () => conditions.every(Boolean));
26
+ }
27
+ }
28
+ return builder;
29
+ };
30
+ }
@@ -0,0 +1,2 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export declare function wrapSyncRule<T extends any[]>(fn: (...args: T) => boolean): (...args: T) => ValidationRuleBuilder;
@@ -0,0 +1,21 @@
1
+ import { ValidationRuleBuilder } from "./validation-rule-builder";
2
+ export function wrapSyncRule(fn) {
3
+ return (...args) => {
4
+ const ruleFn = () => fn(...args);
5
+ const builder = new ValidationRuleBuilder(ruleFn);
6
+ const ruleName = fn.name;
7
+ if (ruleName === "isOptional") {
8
+ builder.runIf(() => fn(...args));
9
+ }
10
+ if (ruleName === "isTrue" || ruleName === "isFalse") {
11
+ builder.runIf(() => fn(...args));
12
+ }
13
+ if (["requiredIf", "requiredUnless", "requiredIfElseEmpty"].includes(ruleName)) {
14
+ const [conditions] = args;
15
+ if (Array.isArray(conditions)) {
16
+ builder.runIf(() => conditions.every(Boolean));
17
+ }
18
+ }
19
+ return builder;
20
+ };
21
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@pogodisco/val",
3
+ "version": "0.0.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "author": "Jakub Bystroński",
8
+ "description": "client / server typescript validator",
9
+ "keywords": [
10
+ "validator",
11
+ "typescript"
12
+ ],
13
+ "license": "MIT",
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "peerDependencies": {
31
+ "@pogodisco/response": "^0.0.1",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@pogodisco/response": "^0.0.1"
36
+ }
37
+ }