@ripetchor/vivi 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ripetchor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # Vivi
2
+
3
+ WARNING: This package is primarily intended for personal use. It may contain bugs or unexpected behavior. Use at your own risk.
4
+
5
+ ## Primitive Validators
6
+
7
+ - `v.string(options?)`
8
+ - `v.number(options?)`
9
+ - `v.boolean(options?)`
10
+ - `v.bigint(options?)`
11
+ - `v.null(options?)`
12
+ - `v.undefined(options?)`
13
+
14
+ ## Other Validators
15
+
16
+ - `v.nullable(validator)`
17
+ - `v.optional(validator)`
18
+ - `v.array(validator, options?)`
19
+ - `v.object(shape, options?)`
20
+ - `v.union([validators], options?)`
21
+ - `v.literal(value, options?)`
22
+ - `v.instance(Class, options?)`
23
+ - `v.date(options?)`
24
+ - `v.email(options?)`
25
+ - `v.unknown()`
26
+ - `v.fallback(validator, defaultValue)`
27
+ - `v.refine(validator, refinements[], options?)`
28
+ - `v.pipe(validator, ...transformFns)`
29
+
30
+ ## Usage Examples
31
+
32
+ ```ts
33
+ import { v } from '@ripetchor/vivi'
34
+ // or
35
+ import v from '@ripetchor/vivi'
36
+ // or
37
+ import { stringValidator, numberValidator, refine /* etc. */ } from '@ripetchor/vivi'
38
+ ```
39
+
40
+ ### Primitive validation
41
+ ```ts
42
+ const name = v.string().parse('Alice');
43
+ console.log(name); // Alice
44
+
45
+ const age = v.number().parse(30);
46
+ console.log(age); // 30
47
+
48
+ const active = v.boolean().parse(true);
49
+ console.log(active); // true
50
+ ```
51
+
52
+ ### Nullable and optional
53
+ ```ts
54
+ const nullableName = v.nullable(v.string()).parse(null);
55
+ console.log(nullableName); // null
56
+
57
+ const optionalAge = v.optional(v.number()).parse(undefined);
58
+ console.log(optionalAge); // undefined
59
+ ```
60
+
61
+ ### Array validation
62
+ ```ts
63
+ const numbers = v.array(v.number()).parse([1, 2, 3]);
64
+ console.log(numbers); // [1, 2, 3]
65
+
66
+ const users = v.array(v.object({ name: v.string(), age: v.number() })).parse([
67
+ { name: "Lana", age: 28 },
68
+ { name: "Mikaela", age: 25, friends: ["Nicole"] },
69
+ { name: "Elsa", age: 28, job: "dev" },
70
+ ]);
71
+ console.log(users); // [{ name: 'Lana', age: 28 }, { name: 'Mikaela', age: 25 }, { name: 'Elsa', age: 28 }]
72
+ ```
73
+
74
+ ### Object validation
75
+ ```ts
76
+ const exactUser = v.object({ name: v.string(), age: v.number() }, { mode: 'exact' }).parse({ name: 'Alice', age: 25 });
77
+ console.log(exactUser); // { name: 'Alice', age: 25 }
78
+
79
+ const stripUser = v.object({ name: v.string() }, { mode: 'strip' }).parse({ name: 'Bob', age: 30 });
80
+ console.log(stripUser); // { name: 'Bob' }
81
+
82
+ const passthroughUser = v.object({ name: v.string() }, { mode: 'passthrough' }).parse({ name: 'Charlie', age: 40 });
83
+ console.log(passthroughUser); // { name: 'Charlie', age: 40 }
84
+ ```
85
+
86
+ ### Union validation
87
+ ```ts
88
+ const value = v.union([v.string(), v.number()]).parse('Hello');
89
+ console.log(value); // 'Hello'
90
+ ```
91
+
92
+ ### Literal validation
93
+ ```ts
94
+ const l1 = v.literal("yes").parse("yes");
95
+ console.log(l1); // 'yes'
96
+
97
+ v.literal("yes").parse("yeS");
98
+ // error
99
+ ```
100
+
101
+ ### Refinements
102
+ ```ts
103
+ const schema = refine(
104
+ v.string(),
105
+ [
106
+ (value) => value.length === 5 || "length must be 5",
107
+ (value) => /^\d+$/.test(value) || "contains only numbers",
108
+ ],
109
+ { abort: true },
110
+ );
111
+
112
+ const result = schema.safeParse("abc");
113
+
114
+ if (!result.success) {
115
+ console.log(result.error.issues); // [ { path: [], message: 'length must be 5' } ]
116
+ } else {
117
+ console.log(result.data);
118
+ }
119
+ ```
120
+
121
+ ### Fallback
122
+ ```ts
123
+ const fallbackValue = v.fallback(v.number(), 42).parse('invalid');
124
+ console.log(fallbackValue); // 42
125
+ ```
126
+
127
+ ### Email validation
128
+ ```ts
129
+ const email = v.email().parse('test@example.com');
130
+ console.log(email); // 'test@example.com'
131
+ ```
132
+
133
+ ### Date validation
134
+ ```ts
135
+ const birthday = v.date().parse(new Date('1990-01-01'));
136
+ console.log(birthday); // 1990-01-01T00:00:00.000Z
137
+ ```
138
+
139
+ ### Pipe transformations
140
+ ```ts
141
+ const transformed = v.pipe(
142
+ v.string(),
143
+ (s: string) => s.trim(),
144
+ (s: string) => s.toUpperCase(),
145
+ ).parse(' hello ');
146
+ console.log(transformed); // 'HELLO'
147
+ ```
148
+
149
+ ### Safe parsing
150
+ ```ts
151
+ const result1 = v.number().safeParse(123);
152
+ console.log(result1); // { success: true, data: 123 }
153
+
154
+ const result2 = v.number().safeParse('not a number');
155
+ console.log(result2); // { success: false, error: ViviError }
156
+ ```
157
+
158
+ ### Abort on first issue
159
+ ```ts
160
+ try {
161
+ v.array(v.number(), { abort: true }).parse([1, "x", 3, "y"]);
162
+ } catch (err) {
163
+ if (err instanceof ViviError) {
164
+ console.log("Aborted on first error:", err.issues);
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Pattern matching (`match`)
170
+
171
+ `match` is a alternative to `if / else` for handling the result of `safeParse`.
172
+
173
+ - enforces handling of all possible states
174
+
175
+ - provides proper type narrowing
176
+
177
+ - eliminates if (result.success) checks
178
+
179
+ ```ts
180
+ const schema = v.string();
181
+
182
+ const result = schema.safeParse("hello");
183
+
184
+ v.match(
185
+ result,
186
+ (data) => {
187
+ console.log("Success:", data);
188
+ },
189
+ (error) => {
190
+ console.log("Validation failed:", error.issues);
191
+ },
192
+ );
193
+
194
+ // Еhe return type is inferred from the callbacks.
195
+ const value = v.match(
196
+ result,
197
+ (data) => data.toUpperCase(),
198
+ () => "DEFAULT",
199
+ );
200
+ // value: string
201
+ ```
202
+
203
+ ### Type inference
204
+ ```ts
205
+ const userValidator = v.object({ name: v.string(), age: v.number() });
206
+ type User = v.infer<typeof userValidator>;
207
+
208
+ const user: User = { name: 'Alice', age: 25 };
209
+ console.log(user); // { name: 'Alice', age: 25 }
210
+ ```
@@ -0,0 +1,220 @@
1
+ //#region src/error.d.ts
2
+ declare class ViviError extends Error {
3
+ readonly issues: ReadonlyArray<ViviIssue>;
4
+ constructor(issues: ReadonlyArray<ViviIssue>);
5
+ static single(message: string, path: Path): ViviError;
6
+ merge(other: ViviError): ViviError;
7
+ }
8
+ //#endregion
9
+ //#region src/types.d.ts
10
+ type Prettify<T> = { [K in keyof T]: T[K] } & {};
11
+ interface SafeParseSuccess<T> {
12
+ success: true;
13
+ data: T;
14
+ }
15
+ interface SafeParseFailure {
16
+ success: false;
17
+ error: ViviError;
18
+ }
19
+ type SafeParseResult<T> = SafeParseSuccess<T> | SafeParseFailure;
20
+ interface ViviValidator<T> {
21
+ parse(input: unknown, path?: Path): T;
22
+ safeParse(input: unknown): SafeParseResult<T>;
23
+ }
24
+ type Infer<T> = T extends ViviValidator<infer U> ? U : never;
25
+ type ErrorFn = (input: unknown) => string;
26
+ type ParseFn<T> = (input: unknown, path: Path) => T;
27
+ type RefineFn<T> = (value: T) => boolean | string;
28
+ type TransformFn<T, U> = (value: T) => U;
29
+ type ErrorMessage = string | ErrorFn;
30
+ interface ValidatorOptions {
31
+ error?: ErrorMessage;
32
+ }
33
+ type Path = ReadonlyArray<string | number>;
34
+ interface ViviIssue {
35
+ readonly path: Path;
36
+ readonly message: string;
37
+ }
38
+ type InferUnion<T extends readonly ViviValidator<unknown>[]> = T extends [infer First, ...infer Rest extends readonly ViviValidator<unknown>[]] ? (First extends ViviValidator<infer O> ? O : never) | InferUnion<Rest> : never;
39
+ type OptionalKeys<T extends Record<string, ViviValidator<unknown>>> = { [K in keyof T]: undefined extends Infer<T[K]> ? K : never }[keyof T];
40
+ type RequiredKeys<T extends Record<string, ViviValidator<unknown>>> = Exclude<keyof T, OptionalKeys<T>>;
41
+ type ObjectShape<T extends Record<string, ViviValidator<unknown>>> = Prettify<{ [K in RequiredKeys<T>]: Infer<T[K]> } & { [K in OptionalKeys<T>]?: Exclude<Infer<T[K]>, undefined> }>;
42
+ //#endregion
43
+ //#region src/array-validator.d.ts
44
+ interface ArrayValidatorOptions extends ValidatorOptions {
45
+ abort?: boolean;
46
+ }
47
+ declare function arrayValidator<T>(validator: ViviValidator<T>, options?: ArrayValidatorOptions): ViviValidator<T[]>;
48
+ //#endregion
49
+ //#region src/bigint-validator.d.ts
50
+ declare function bigintValidator(options?: ValidatorOptions): ViviValidator<bigint>;
51
+ //#endregion
52
+ //#region src/boolean-validator.d.ts
53
+ declare function booleanValidator(options?: ValidatorOptions): ViviValidator<boolean>;
54
+ //#endregion
55
+ //#region src/date-validator.d.ts
56
+ declare function dateValidator(options?: ValidatorOptions): ViviValidator<Date>;
57
+ //#endregion
58
+ //#region src/email-validator.d.ts
59
+ interface EmailValidatorOptions extends ValidatorOptions {
60
+ pattern?: RegExp;
61
+ }
62
+ declare function emailValidator(options?: EmailValidatorOptions): ViviValidator<string>;
63
+ //#endregion
64
+ //#region src/fallback.d.ts
65
+ declare function fallback<T>(validator: ViviValidator<T>, defaultValue: T): ViviValidator<T>;
66
+ //#endregion
67
+ //#region src/instance-validator.d.ts
68
+ declare function instanceValidator<T>(ctor: new (...args: any[]) => T, options?: ValidatorOptions): ViviValidator<T>;
69
+ //#endregion
70
+ //#region src/literal-validator.d.ts
71
+ declare function literalValidator<T extends string | number | boolean>(value: T, options?: ValidatorOptions): ViviValidator<T>;
72
+ //#endregion
73
+ //#region src/null-validator.d.ts
74
+ declare function nullValidator(options?: ValidatorOptions): ViviValidator<null>;
75
+ //#endregion
76
+ //#region src/nullable-validator.d.ts
77
+ declare function nullableValidator<T>(validator: ViviValidator<T>): ViviValidator<T | null>;
78
+ //#endregion
79
+ //#region src/number-validator.d.ts
80
+ declare function numberValidator(options?: ValidatorOptions): ViviValidator<number>;
81
+ //#endregion
82
+ //#region src/object-validator.d.ts
83
+ type ObjectMode = "exact" | "passthrough" | "strip";
84
+ interface ObjectValidatorOptions extends ValidatorOptions {
85
+ mode?: ObjectMode;
86
+ abort?: boolean;
87
+ }
88
+ declare function objectValidator<T extends Record<string, ViviValidator<unknown>>>(shape: T, options?: ObjectValidatorOptions): ViviValidator<ObjectShape<T>>;
89
+ //#endregion
90
+ //#region src/optional-validator.d.ts
91
+ declare function optionalValidator<T>(validator: ViviValidator<T>): ViviValidator<T | undefined>;
92
+ //#endregion
93
+ //#region src/pipe.d.ts
94
+ declare function pipe<A>(a: ViviValidator<A>): ViviValidator<A>;
95
+ declare function pipe<A, B>(a: ViviValidator<A>, ab: TransformFn<A, B>): ViviValidator<B>;
96
+ declare function pipe<A, B, C>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>): ViviValidator<C>;
97
+ declare function pipe<A, B, C, D>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>): ViviValidator<D>;
98
+ declare function pipe<A, B, C, D, E>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>): ViviValidator<E>;
99
+ declare function pipe<A, B, C, D, E, F>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>): ViviValidator<F>;
100
+ declare function pipe<A, B, C, D, E, F, G>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>): ViviValidator<G>;
101
+ declare function pipe<A, B, C, D, E, F, G, H>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>): ViviValidator<H>;
102
+ declare function pipe<A, B, C, D, E, F, G, H, I>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>): ViviValidator<I>;
103
+ declare function pipe<A, B, C, D, E, F, G, H, I, J>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>): ViviValidator<J>;
104
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>): ViviValidator<K$1>;
105
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>): ViviValidator<L>;
106
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>): ViviValidator<M>;
107
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>): ViviValidator<N>;
108
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>): ViviValidator<O>;
109
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>): ViviValidator<P>;
110
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>): ViviValidator<Q>;
111
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>): ViviValidator<R>;
112
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>): ViviValidator<S>;
113
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>): ViviValidator<T>;
114
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>): ViviValidator<U>;
115
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U, V>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>, uv: TransformFn<U, V>): ViviValidator<V>;
116
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U, V, W>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>, uv: TransformFn<U, V>, vw: TransformFn<V, W>): ViviValidator<W>;
117
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U, V, W, X>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>, uv: TransformFn<U, V>, vw: TransformFn<V, W>, wx: TransformFn<W, X>): ViviValidator<X>;
118
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>, uv: TransformFn<U, V>, vw: TransformFn<V, W>, wx: TransformFn<W, X>, xy: TransformFn<X, Y>): ViviValidator<Y>;
119
+ declare function pipe<A, B, C, D, E, F, G, H, I, J, K$1, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z>(a: ViviValidator<A>, ab: TransformFn<A, B>, bc: TransformFn<B, C>, cd: TransformFn<C, D>, de: TransformFn<D, E>, ef: TransformFn<E, F>, fg: TransformFn<F, G>, gh: TransformFn<G, H>, hi: TransformFn<H, I>, ij: TransformFn<I, J>, jk: TransformFn<J, K$1>, kl: TransformFn<K$1, L>, lm: TransformFn<L, M>, mn: TransformFn<M, N>, no: TransformFn<N, O>, op: TransformFn<O, P>, pq: TransformFn<P, Q>, qr: TransformFn<Q, R>, rs: TransformFn<R, S>, st: TransformFn<S, T>, tu: TransformFn<T, U>, uv: TransformFn<U, V>, vw: TransformFn<V, W>, wx: TransformFn<W, X>, xy: TransformFn<X, Y>, yz: TransformFn<Y, Z>): ViviValidator<Z>;
120
+ //#endregion
121
+ //#region src/refine.d.ts
122
+ interface RefineOptions {
123
+ abort?: boolean;
124
+ }
125
+ declare function refine<T>(validator: ViviValidator<T>, refinements: RefineFn<T>[], options?: RefineOptions): ViviValidator<T>;
126
+ //#endregion
127
+ //#region src/shared/create-validator.d.ts
128
+ declare function createValidator<T>(parseFn: ParseFn<T>): ViviValidator<T>;
129
+ //#endregion
130
+ //#region src/shared/match.d.ts
131
+ declare function match<T, R>(result: SafeParseResult<T>, onsuccess: (data: T) => R, onfailure: (error: ViviError) => R): R;
132
+ //#endregion
133
+ //#region src/string-validator.d.ts
134
+ declare function stringValidator(options?: ValidatorOptions): ViviValidator<string>;
135
+ //#endregion
136
+ //#region src/undefined-validator.d.ts
137
+ declare function undefinedValidator(options?: ValidatorOptions): ViviValidator<undefined>;
138
+ //#endregion
139
+ //#region src/union-validator.d.ts
140
+ declare function unionValidator<T extends ReadonlyArray<ViviValidator<unknown>>>(validators: readonly [...T], options?: ValidatorOptions): ViviValidator<InferUnion<T>>;
141
+ //#endregion
142
+ //#region src/unknown-validator.d.ts
143
+ declare function unknownValidator(): ViviValidator<unknown>;
144
+ //#endregion
145
+ //#region src/refinement-utils/number-refinements.d.ts
146
+ declare function min(minValue: number, message?: string): (value: number) => string | true;
147
+ declare function max(maxValue: number, message?: string): (value: number) => string | true;
148
+ declare function gt(minValue: number, message?: string): (value: number) => string | true;
149
+ declare function lt(maxValue: number, message?: string): (value: number) => string | true;
150
+ declare function integer(message?: string): (value: number) => string | true;
151
+ declare function finite(message?: string): (value: number) => string | true;
152
+ declare function positive(message?: string): (value: number) => string | true;
153
+ declare function negative(message?: string): (value: number) => string | true;
154
+ declare function between(minValue: number, maxValue: number, message?: string): (value: number) => string | true;
155
+ declare function even(message?: string): (value: number) => string | true;
156
+ declare function odd(message?: string): (value: number) => string | true;
157
+ //#endregion
158
+ //#region src/refinement-utils/string-refinements.d.ts
159
+ declare function minLength(min: number, message?: string): (value: string) => string | true;
160
+ declare function maxLength(max: number, message?: string): (value: string) => string | true;
161
+ declare function length(len: number, message?: string): (value: string) => string | true;
162
+ declare function pattern(regex: RegExp, message?: string): (value: string) => string | true;
163
+ declare function startsWith(prefix: string, message?: string): (value: string) => string | true;
164
+ declare function endsWith(suffix: string, message?: string): (value: string) => string | true;
165
+ declare function nonEmpty(message?: string): (value: string) => string | true;
166
+ declare function includes(substring: string, message?: string): (value: string) => string | true;
167
+ declare function notIncludes(substring: string, message?: string): (value: string) => string | true;
168
+ declare function trimmed(message?: string): (value: string) => string | true;
169
+ declare function lowercase(message?: string): (value: string) => string | true;
170
+ declare function uppercase(message?: string): (value: string) => string | true;
171
+ declare function uuid4(message?: string): (value: string) => string | true;
172
+ //#endregion
173
+ //#region src/transform-utils/number-transforms.d.ts
174
+ declare function round(): (value: number) => number;
175
+ declare function floor(): (value: number) => number;
176
+ declare function ceil(): (value: number) => number;
177
+ declare function clamp(minValue: number, maxValue: number): (value: number) => number;
178
+ declare function abs(): (value: number) => number;
179
+ //#endregion
180
+ //#region src/transform-utils/string-transforms.d.ts
181
+ declare function trim(): (value: string) => string;
182
+ declare function toLowerCase(): (value: string) => string;
183
+ declare function toUpperCase(): (value: string) => string;
184
+ interface ReplaceOptions {
185
+ global?: boolean;
186
+ ignoreCase?: boolean;
187
+ }
188
+ declare function replace(searchValue: string | RegExp, replaceValue: string, options?: ReplaceOptions): (value: string) => string;
189
+ declare function truncateEnd(maxLength: number, suffix?: string): (value: string) => string;
190
+ declare function truncateStart(maxLength: number, suffix?: string): (value: string) => string;
191
+ declare function normalizeSpaces(): (value: string) => string;
192
+ //#endregion
193
+ //#region src/index.d.ts
194
+ declare const v: {
195
+ array: typeof arrayValidator;
196
+ bigint: typeof bigintValidator;
197
+ boolean: typeof booleanValidator;
198
+ date: typeof dateValidator;
199
+ email: typeof emailValidator;
200
+ fallback: typeof fallback;
201
+ instance: typeof instanceValidator;
202
+ literal: typeof literalValidator;
203
+ null: typeof nullValidator;
204
+ nullable: typeof nullableValidator;
205
+ number: typeof numberValidator;
206
+ object: typeof objectValidator;
207
+ optional: typeof optionalValidator;
208
+ string: typeof stringValidator;
209
+ undefined: typeof undefinedValidator;
210
+ union: typeof unionValidator;
211
+ unknown: typeof unknownValidator;
212
+ refine: typeof refine;
213
+ pipe: typeof pipe;
214
+ match: typeof match;
215
+ };
216
+ declare namespace v {
217
+ type infer<T extends ViviValidator<unknown>> = Infer<T>;
218
+ }
219
+ //#endregion
220
+ export { ViviError, abs, arrayValidator, between, bigintValidator, booleanValidator, ceil, clamp, createValidator as customValidator, dateValidator, v as default, v, emailValidator, endsWith, even, fallback, finite, floor, gt, includes, instanceValidator, integer, length, literalValidator, lowercase, lt, match, max, maxLength, min, minLength, negative, nonEmpty, normalizeSpaces, notIncludes, nullValidator, nullableValidator, numberValidator, objectValidator, odd, optionalValidator, pattern, pipe, positive, refine, replace, round, startsWith, stringValidator, toLowerCase, toUpperCase, trim, trimmed, truncateEnd, truncateStart, undefinedValidator, unionValidator, unknownValidator, uppercase, uuid4 };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var e=class e extends Error{issues;constructor(t){super(`Vivi validation error`),this.name=e.name,this.issues=t}static single(t,n){return new e([{message:t,path:n}])}merge(t){return new e([...this.issues,...t.issues])}};function t(e,t,n){for(let r=0;r<t.length;r++){let i=t[r],a=[];for(let e=0;e<n.length;e++)a.push(n[e]);for(let e=0;e<i.path.length;e++)a.push(i.path[e]);e.push({message:i.message,path:a})}}function n(t){return{parse(e,n=[]){return t(e,n)},safeParse(n){try{return{success:!0,data:t(n,[])}}catch(t){if(t instanceof e)return{success:!1,error:t};let n=t instanceof Error?t.message:`Unknown validation error`;return{success:!1,error:e.single(n,[])}}}}}function r(e,t,n){return typeof e==`function`?e(n):e??t}function i(i,a){return n((n,o)=>{if(!Array.isArray(n))throw e.single(r(a?.error,`Expected array`,n),o);let s=[],c=[];for(let r=0;r<n.length;r++){let l=i.safeParse(n[r]);if(l.success)s[r]=l.data;else if(t(c,l.error.issues,o.concat(r)),a?.abort)throw new e(c)}if(c.length>0)throw new e(c);return s})}function a(t){return n((n,i)=>{if(typeof n!=`bigint`)throw e.single(r(t?.error,`Expected bigint`,n),i);return n})}function o(t){return n((n,i)=>{if(typeof n!=`boolean`)throw e.single(r(t?.error,`Expected boolean`,n),i);return n})}function s(t){return n((n,i)=>{if(!(n instanceof Date)||isNaN(n.getTime()))throw e.single(r(t?.error,`Expected Date`,n),i);return n})}const c=/^(?!\.)(?!.*\.\.)([a-z0-9_'+\-\.]*)[a-z0-9_+\-]@([a-z0-9][a-z0-9\-]*\.)+[a-z]{2,}$/i;function l(t){let i=t?.pattern??c;return n((n,a)=>{if(typeof n!=`string`)throw e.single(r(t?.error,`Expected string`,n),a);if(!i.test(n))throw e.single(r(t?.error,`Invalid email format`,n),a);return n})}function u(t,r){return n((n,i)=>{try{return t.parse(n,i)}catch(t){if(t instanceof e)return r;throw t}})}function d(t,i){return n((n,a)=>{if(!(n instanceof t))throw e.single(r(i?.error,`Expected instance of ${t.name}`,n),a);return n})}function f(t,i){return n((n,a)=>{if(n!==t)throw e.single(r(i?.error,`Expected literal ${String(t)}`,n),a);return t})}function p(t){return n((n,i)=>{if(n!==null)throw e.single(r(t?.error,`Expected null`,n),i);return null})}function m(e){return n((t,n)=>t===null?null:e.parse(t,n))}function h(t){return n((n,i)=>{if(typeof n!=`number`)throw e.single(r(t?.error,`Expected number`,n),i);return n})}function g(i,a){let o=a?.mode??`strip`;return n((n,s)=>{if(typeof n!=`object`||!n||Array.isArray(n))throw e.single(r(a?.error,`Expected object`,n),s);let c=n,l={},u=[],d=Object.keys(c);for(let n=0;n<d.length;n++){let f=d[n],p=c[f],m=i[f];if(m!==void 0){let n=m.safeParse(p);if(n.success)l[f]=n.data;else if(t(u,n.error.issues,s.concat(f)),a?.abort)throw new e(u)}else o===`exact`?u.push({message:r(void 0,`Unexpected property`,p),path:s.concat(f)}):o===`passthrough`&&(l[f]=p)}if(u.length>0)throw new e(u);return l})}function _(e){return n((t,n)=>{if(t!==void 0)return e.parse(t,n)})}function v(e,...t){return n((n,r)=>{let i=e.parse(n,r);for(let e=0;e<t.length;e++)i=t[e](i);return i})}function y(t,r,i){return n((n,a)=>{let o=t.parse(n,a),s=[];for(let e=0;e<r.length;e++){let t=r[e](o);if(t===!1){if(s.push({path:a,message:`Refinement failed`}),i?.abort)break}else if(typeof t==`string`&&(s.push({path:a,message:t}),i?.abort))break}if(s.length>0)throw new e(s);return o})}function b(e,t,n){return e.success?t(e.data):n(e.error)}function x(t){return n((n,i)=>{if(typeof n!=`string`)throw e.single(r(t?.error,`Expected string`,n),i);return n})}function S(t){return n((n,i)=>{if(n!==void 0)throw e.single(r(t?.error,`Expected undefined`,n),i)})}function C(i,a){return n((n,o)=>{let s=[];for(let e=0;e<i.length;e++){let r=i[e].safeParse(n);if(r.success)return r.data;t(s,r.error.issues,o)}throw s.length>0?new e(s):e.single(r(a?.error,`No union variant matched`,n),o)})}function w(){return n(e=>e)}function T(e,t){return function(n){return n>=e||t||`Must be >= ${e}`}}function ee(e,t){return function(n){return n<=e||t||`Must be <= ${e}`}}function E(e,t){return function(n){return n>e||t||`Must be > ${e}`}}function D(e,t){return function(n){return n<e||t||`Must be < ${e}`}}function O(e){return function(t){return Number.isInteger(t)||e||`Must be an integer`}}function k(e){return function(t){return Number.isFinite(t)||e||`Must be a finite number`}}function A(e){return function(t){return t>0||e||`Must be positive`}}function j(e){return function(t){return t<0||e||`Must be negative`}}function M(e,t,n){return function(r){return r>=e&&r<=t||n||`Must be between ${e} and ${t}`}}function N(e){return function(t){return t%2==0||e||`Must be an even number`}}function P(e){return function(t){return t%2!=0||e||`Must be an odd number`}}function F(e,t){return function(n){return n.length>=e||t||`Must have at least ${e} characters`}}function I(e,t){return function(n){return n.length<=e||t||`Must have at most ${e} characters`}}function L(e,t){return function(n){return n.length===e||t||`Must have exactly ${e} characters`}}function R(e,t){return function(n){return e.test(n)||t||`Invalid format`}}function z(e,t){return function(n){return n.startsWith(e)||t||`Must start with "${e}"`}}function B(e,t){return function(n){return n.endsWith(e)||t||`Must end with "${e}"`}}function V(e){return function(t){return t.length>0||e||`Must not be empty`}}function te(e,t){return function(n){return n.includes(e)||t||`Must include "${e}"`}}function H(e,t){return function(n){return!n.includes(e)||t||`Must not include "${e}"`}}function U(e){return function(t){return t.trim()===t||e||`Must not have leading or trailing spaces`}}function W(e){return function(t){return t===t.toLowerCase()||e||`Must be lowercase`}}function G(e){return function(t){return t===t.toUpperCase()||e||`Must be uppercase`}}function K(e){let t=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return function(n){return t.test(n)||e||`Must be a valid UUID v4`}}function q(){return function(e){return Math.round(e)}}function J(){return function(e){return Math.floor(e)}}function Y(){return function(e){return Math.ceil(e)}}function X(e,t){return function(n){return Math.min(Math.max(n,e),t)}}function Z(){return function(e){return Math.abs(e)}}function Q(){return function(e){return e.trim()}}function ne(){return function(e){return e.toLowerCase()}}function re(){return function(e){return e.toUpperCase()}}function ie(e,t,n){return function(r){if(typeof e==`string`){let i=``;return n?.global&&(i+=`g`),n?.ignoreCase&&(i+=`i`),r.replace(new RegExp(e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),i),t)}else return r.replace(e,t)}}function ae(e,t=``){return function(n){return n.length>e?n.slice(0,e)+t:n}}function oe(e,t=``){return function(n){return n.length<=e?n:t+n.slice(n.length-e)}}function se(){return function(e){return e.replace(/\s+/g,` `).trim()}}const $={array:i,bigint:a,boolean:o,date:s,email:l,fallback:u,instance:d,literal:f,null:p,nullable:m,number:h,object:g,optional:_,string:x,undefined:S,union:C,unknown:w,refine:y,pipe:v,match:b};var ce=$;export{e as ViviError,Z as abs,i as arrayValidator,M as between,a as bigintValidator,o as booleanValidator,Y as ceil,X as clamp,n as customValidator,s as dateValidator,ce as default,l as emailValidator,B as endsWith,N as even,u as fallback,k as finite,J as floor,E as gt,te as includes,d as instanceValidator,O as integer,L as length,f as literalValidator,W as lowercase,D as lt,b as match,ee as max,I as maxLength,T as min,F as minLength,j as negative,V as nonEmpty,se as normalizeSpaces,H as notIncludes,p as nullValidator,m as nullableValidator,h as numberValidator,g as objectValidator,P as odd,_ as optionalValidator,R as pattern,v as pipe,A as positive,y as refine,ie as replace,q as round,z as startsWith,x as stringValidator,ne as toLowerCase,re as toUpperCase,Q as trim,U as trimmed,ae as truncateEnd,oe as truncateStart,S as undefinedValidator,C as unionValidator,w as unknownValidator,G as uppercase,K as uuid4,$ as v};
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@ripetchor/vivi",
3
+ "version": "0.0.1",
4
+ "scripts": {
5
+ "build": "tsdown",
6
+ "dev": "tsdown --watch",
7
+ "test": "vitest",
8
+ "typecheck": "tsc --noEmit"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/ripetchor/vivi.git"
13
+ },
14
+ "author": "ripetchor",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "license": "MIT",
22
+ "main": "./dist/index.mjs",
23
+ "module": "./dist/index.mjs",
24
+ "types": "./dist/index.d.mts",
25
+ "exports": {
26
+ ".": "./dist/index.mjs",
27
+ "./package.json": "./package.json"
28
+ },
29
+ "type": "module",
30
+ "bugs": {
31
+ "url": "https://github.com/ripetchor/vivi/issues"
32
+ },
33
+ "homepage": "https://github.com/ripetchor/vivi#readme",
34
+ "devDependencies": {
35
+ "@types/node": "^24.10.1",
36
+ "bumpp": "^10.3.1",
37
+ "tsdown": "^0.18.3",
38
+ "typescript": "^5.9.3",
39
+ "vitest": "^4.0.9"
40
+ }
41
+ }