bguard 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) 2024 Nikola Blagojevic
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,145 @@
1
+ # bguard
2
+
3
+ **bguard** is a powerful, flexible, and type-safe validation library for TypeScript. It allows developers to define validation schemas for their data structures and ensures that data conforms to the expected types and constraints.
4
+
5
+ ### Features
6
+
7
+ - **Type Inference**: Automatically infer TypeScript types from your validation schemas.
8
+ - **Custom Assertions**: Add custom validation logic for your schemas.
9
+ - **Chaining Methods**: Easily chain methods for complex validations.
10
+ - **Nested Validation**: Supports complex data structures, including arrays and objects.
11
+ - **Optional and Nullable Support**: Fine-grained control over optional and nullable fields.
12
+ - **Small Bundle Size**: Each assertion is in its own file, minimizing your final bundle size.
13
+ - **Lightweight**: No dependencies and optimized for performance.
14
+
15
+ ### Installation
16
+
17
+ ```bash
18
+ npm install bguard
19
+ ```
20
+
21
+ ### Usage
22
+
23
+ Here’s a basic example of how to use `bguard` to define and validate a schema.
24
+
25
+ #### Defining a Schema
26
+
27
+ Let's define a schema for a Student object:
28
+
29
+ ```typeScript
30
+
31
+ import { parseSchema, InferType, string, number, array, object, boolean } from 'bguard';
32
+ import { email } from 'bguard/asserts/string/email';
33
+ import { min } from 'bguard/asserts/number/min';
34
+ import { max } from 'bguard/asserts/number/max';
35
+
36
+ // Example: Student Schema
37
+ const studentSchema = object({
38
+ email: string().optional().custom(email()),
39
+ age: number().custom(min(18), max(120)),
40
+ address: string().nullable(),
41
+ classes: array(
42
+ object({
43
+ name: string(),
44
+ mandatory: boolean(),
45
+ rooms: array(number()),
46
+ }).optional()
47
+ ),
48
+ verified: boolean().optional(),
49
+ });
50
+
51
+ ```
52
+
53
+ #### Inferring TypeScript Types
54
+
55
+ Using the InferType utility, you can infer the TypeScript type of the schema:
56
+
57
+ ```typescript
58
+
59
+ type StudentSchema = InferType<typeof studentSchema>;
60
+
61
+ ```
62
+
63
+ This will generate the following type:
64
+
65
+ ```typeScript
66
+
67
+ type StudentSchema = {
68
+ age: number;
69
+ address: string | null;
70
+ classes: ({
71
+ name: string;
72
+ mandatory: boolean;
73
+ rooms: number[];
74
+ } | undefined)[];
75
+ email?: string | undefined;
76
+ verified?: boolean | undefined;
77
+ }
78
+
79
+ ```
80
+
81
+ #### Validating Data
82
+
83
+ To validate data against the defined schema, use the parseSchema function:
84
+
85
+ ```typeScript
86
+
87
+ const studentData = {
88
+ age: 21,
89
+ address: '123 Main St',
90
+ classes: [
91
+ {
92
+ name: 'Math 101',
93
+ mandatory: true,
94
+ rooms: [101, 102],
95
+ },
96
+ ],
97
+ email: 'student@example.com',
98
+ };
99
+
100
+ const validatedData = parseSchema(studentSchema, studentData);
101
+
102
+
103
+ ```
104
+
105
+ If the data does not conform to the schema, an error will be thrown.
106
+
107
+
108
+
109
+ ### Chaining Methods
110
+
111
+ - `nullable()`: Allows the value to be null.
112
+ - `optional()`: Allows the value to be undefined.
113
+
114
+ Example:
115
+
116
+ ```typeScript
117
+
118
+ const schema = string().nullable().optional();
119
+ ```
120
+
121
+ - String Literals:
122
+ `string().equalTo('myStringValue')` will infer 'myStringValue' as the type.
123
+
124
+ - Number Literals:
125
+ `number().equalTo(42)` will infer 42 as the type.
126
+
127
+ - Boolean Literals:
128
+ `boolean().onlyTrue()` will infer true as the type.
129
+ `boolean().onlyFalse()` will infer false as the type.
130
+
131
+
132
+
133
+ ### Custom Assertions
134
+ You can extend the validation with custom assertions:
135
+
136
+ ```typeScript
137
+ import { min } from 'bguard/asserts/number/min';
138
+ import { max } from 'bguard/asserts/number/max';
139
+
140
+ const ageSchema = number().custom(min(18), max(120));
141
+ ```
142
+ Assertions are imported from specific paths for better tree-shaking and smaller bundle sizes.
143
+
144
+ ### Contributing
145
+ Contributions are welcome! Please open an issue or submit a pull request for any bugs or feature requests.
@@ -0,0 +1,254 @@
1
+ declare const ctxSymbol: unique symbol;
2
+
3
+ type RequiredValidation = (received: any, pathToError: string) => void;
4
+ type ObjectShapeSchemaType = Record<string, CommonSchema>;
5
+ type PrimitiveType = 'number' | 'string' | 'boolean' | 'undefined' | 'object' | 'function' | 'symbol' | 'bigint';
6
+ interface ValidatorContext {
7
+ type: PrimitiveType[];
8
+ isNullable?: boolean;
9
+ isOptional?: boolean;
10
+ requiredValidations: RequiredValidation[];
11
+ array?: CommonSchema;
12
+ object?: ObjectShapeSchemaType;
13
+ }
14
+ declare class CommonSchema {
15
+ [ctxSymbol]: ValidatorContext;
16
+ constructor(ctx: ValidatorContext);
17
+ /**
18
+ * @param validators - One or more custom validation functions.
19
+ * @returns {this} The schema instance with the added custom validation.
20
+ */
21
+ custom(...validators: RequiredValidation[]): this;
22
+ /**
23
+ * Marks the schema as nullable, allowing the value to be `null`.
24
+ *
25
+ * @returns {WithNull<this>} The schema instance marked as nullable.
26
+ */
27
+ nullable(): WithNull<this>;
28
+ /**
29
+ * Marks the schema as optional, allowing the value to be `undefined`.
30
+ *
31
+ * @returns {WithUndefined<this>}} The schema instance marked as optional.
32
+ */
33
+ optional(): WithUndefined<this>;
34
+ }
35
+ type WithNull<T extends CommonSchema> = T & {
36
+ validation_null: true;
37
+ };
38
+ type WithUndefined<T extends CommonSchema> = T & {
39
+ validation_undefined: true;
40
+ };
41
+ type TypeMapping = {
42
+ number: number;
43
+ string: string;
44
+ boolean: boolean;
45
+ undefined: undefined;
46
+ object: object;
47
+ function: Function;
48
+ symbol: symbol;
49
+ bigint: bigint;
50
+ };
51
+ type WithMix<Y = unknown> = CommonSchema & {
52
+ validation_mix: Y;
53
+ };
54
+ type ExtractFromMix<T> = T extends WithMix<infer X> ? X : never;
55
+ type MapMixTypes<T extends PrimitiveType[]> = T extends (infer U)[] ? U extends keyof TypeMapping ? TypeMapping[U] : never : never;
56
+
57
+ declare class ArraySchema extends CommonSchema {
58
+ _array: number;
59
+ constructor(ctx: ValidatorContext, arraySchema: CommonSchema);
60
+ private validateArrayEntry;
61
+ }
62
+ type WithArray<Y extends CommonSchema> = ArraySchema & {
63
+ validation_array: Y;
64
+ };
65
+ type ExtractFromArray<T> = T extends WithArray<infer X> ? X : never;
66
+
67
+ declare class BooleanSchema extends CommonSchema {
68
+ _boolean: number;
69
+ /**
70
+ * Restricts the schema to exactly match the boolean value true and infers the true value as the TypeScript type.
71
+ *
72
+ * @returns - The schema instance restricted to the value true, with the true value inferred as the TypeScript type
73
+ *
74
+ * @example - boolean().onlyTrue(); // Infers the type true
75
+ */
76
+ onlyTrue(): WithBoolean<this, true>;
77
+ /**
78
+ * Restricts the schema to exactly match the boolean value false and infers the false value as the TypeScript type.
79
+ *
80
+ * @returns - The schema instance restricted to the value false, with the false value inferred as the TypeScript type
81
+ *
82
+ * @example - boolean().onlyFalse(); // Infers the type false
83
+ */
84
+ onlyFalse(): WithBoolean<this, false>;
85
+ }
86
+ type WithBoolean<T extends BooleanSchema, Y = boolean> = T & {
87
+ validation_boolean: Y;
88
+ };
89
+ type ExtractFromBoolean<T> = T extends WithBoolean<BooleanSchema, infer Y> ? Y : never;
90
+
91
+ declare class NumberSchema extends CommonSchema {
92
+ _number: number;
93
+ /**
94
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
95
+ *
96
+ * @param expectedValue - The value that the schema must exactly match.
97
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
98
+ *
99
+ * @example - number().equalTo(42); // Infers the type 42
100
+ */
101
+ equalTo<Y extends number>(expectedValue: Y): WithNumber<this, Y>;
102
+ }
103
+ type WithNumber<T extends NumberSchema, Y = number> = T & {
104
+ validation_number: Y;
105
+ };
106
+ type ExtractFromNumber<T> = T extends WithNumber<NumberSchema, infer Y> ? Y : never;
107
+
108
+ declare class ObjectSchema extends CommonSchema {
109
+ _object: number;
110
+ constructor(ctx: ValidatorContext, shapeSchema: ObjectShapeSchemaType);
111
+ private validateObjectEntry;
112
+ }
113
+ type WithObject<Y extends ObjectShapeSchemaType> = ObjectSchema & {
114
+ validation_object: Y;
115
+ };
116
+
117
+ declare class StringSchema extends CommonSchema {
118
+ _string: number;
119
+ /**
120
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
121
+ *
122
+ * @param expectedValue - The value that the schema must exactly match.
123
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
124
+ *
125
+ * @example - string().equalTo('hello'); // Infers the type 'hello'
126
+ */
127
+ equalTo<Y extends string>(expectedValue: Y): WithString<this, Y>;
128
+ }
129
+ type WithString<T extends StringSchema, Y = string> = T & {
130
+ validation_string: Y;
131
+ };
132
+ type ExtractFromString<T> = T extends WithString<StringSchema, infer Y> ? Y : never;
133
+
134
+ type InferType<T> = T extends WithUndefined<WithNull<WithString<StringSchema>>> ? ExtractFromString<T> | null | undefined : T extends WithUndefined<WithString<StringSchema>> ? ExtractFromString<T> | undefined : T extends WithNull<WithString<StringSchema>> ? ExtractFromString<T> | null : T extends WithString<StringSchema> ? ExtractFromString<T> : T extends WithUndefined<WithNull<StringSchema>> ? string | null | undefined : T extends WithUndefined<StringSchema> ? string | undefined : T extends WithNull<StringSchema> ? string | null : T extends StringSchema ? string : T extends WithUndefined<WithNull<WithNumber<NumberSchema>>> ? ExtractFromNumber<T> | null | undefined : T extends WithUndefined<WithNumber<NumberSchema>> ? ExtractFromNumber<T> | undefined : T extends WithNull<WithNumber<NumberSchema>> ? ExtractFromNumber<T> | null : T extends WithNumber<NumberSchema> ? ExtractFromNumber<T> : T extends WithUndefined<WithNull<NumberSchema>> ? number | null | undefined : T extends WithUndefined<NumberSchema> ? number | undefined : T extends WithNull<NumberSchema> ? number | null : T extends NumberSchema ? number : T extends WithUndefined<WithNull<WithBoolean<BooleanSchema>>> ? ExtractFromBoolean<T> | null | undefined : T extends WithUndefined<WithBoolean<BooleanSchema>> ? ExtractFromBoolean<T> | undefined : T extends WithNull<WithBoolean<BooleanSchema>> ? ExtractFromBoolean<T> | null : T extends WithBoolean<BooleanSchema> ? ExtractFromBoolean<T> : T extends WithUndefined<WithNull<BooleanSchema>> ? boolean | null | undefined : T extends WithUndefined<BooleanSchema> ? boolean | undefined : T extends WithNull<BooleanSchema> ? boolean | null : T extends BooleanSchema ? boolean : T extends WithUndefined<WithNull<ArraySchema>> ? InferType<ExtractFromArray<T>>[] | null | undefined : T extends WithUndefined<ArraySchema> ? InferType<ExtractFromArray<T>>[] | undefined : T extends WithNull<ArraySchema> ? InferType<ExtractFromArray<T>>[] | null : T extends ArraySchema ? InferType<ExtractFromArray<T>>[] : T extends WithUndefined<WithNull<ObjectSchema>> ? ExtractFromObject<T> | null | undefined : T extends WithUndefined<ObjectSchema> ? ExtractFromObject<T> | undefined : T extends WithNull<ObjectSchema> ? ExtractFromObject<T> | null : T extends ObjectSchema ? ExtractFromObject<T> : T extends WithUndefined<WithNull<WithMix>> ? ExtractFromMix<T> | null | undefined : T extends WithUndefined<WithMix> ? ExtractFromMix<T> | undefined : T extends WithNull<WithMix> ? ExtractFromMix<T> | null : T extends WithMix ? ExtractFromMix<T> : unknown;
135
+ type Merge<T> = T extends infer U ? {
136
+ [K in keyof U]: U[K];
137
+ } : never;
138
+ type ExtractFromObject<T extends ObjectSchema> = T extends WithObject<infer X> ? Merge<{
139
+ [K in keyof X as X[K] extends WithUndefined<CommonSchema> ? never : K]: InferType<X[K]>;
140
+ } & {
141
+ [K in keyof X as X[K] extends WithUndefined<CommonSchema> ? K : never]?: InferType<X[K]>;
142
+ }> : unknown;
143
+
144
+ /**
145
+ * Parses and validates a value against the provided schema, returning a type-safe result.
146
+ *
147
+ * This function will throw a `ValidationError` if the value does not conform to the schema.
148
+ * The inferred TypeScript type of the returned value will match the structure defined by the schema.
149
+ *
150
+ * @template T
151
+ * @param {T} schema - The schema to validate the received value against. This schema dictates the expected structure and type of the value.
152
+ * @param {unknown} receivedValue - The value to be validated and parsed according to the schema.
153
+ * @returns {InferType<T>} The validated value, with its TypeScript type inferred from the schema.
154
+ *
155
+ * @throws {ValidationError} If the received value does not match the schema, a `ValidationError` will be thrown.
156
+ * @throws {Error} If an unexpected error occurs during validation, an error will be thrown with a generic message.
157
+ *
158
+ * @example
159
+ * const schema = object({
160
+ * name: string(),
161
+ * age: number(),
162
+ * });
163
+ *
164
+ * const result = parseSchema(schema, { name: 'Alice', age: 30 });
165
+ * // result will be inferred as { name: string; age: number }
166
+ *
167
+ * parseSchema(schema, { name: 'Alice', age: '30' });
168
+ * // Throws ValidationError because 'age' should be a number, not a string.
169
+ */
170
+ declare function parseSchema<T extends CommonSchema>(schema: T, receivedValue: unknown): InferType<T>;
171
+
172
+ /**
173
+ * Creates a new schema for validating number values.
174
+ *
175
+ * @returns {NumberSchema} A new instance of `NumberSchema` for validating numbers.
176
+ *
177
+ * @example
178
+ * const schema = number();
179
+ * parseSchema(schema, 42); // Validates successfully
180
+ * parseSchema(schema, '42'); // Throws a validation error
181
+ */
182
+ declare function number(): NumberSchema;
183
+
184
+ /**
185
+ * Creates a new schema for validating string values.
186
+ *
187
+ * @returns {StringSchema} A new instance of `StringSchema` for validating strings.
188
+ *
189
+ * @example
190
+ * const schema = string();
191
+ * parseSchema(schema, 'hello'); // Validates successfully
192
+ * parseSchema(schema, 123); // Throws a validation error
193
+ */
194
+ declare function string(): StringSchema;
195
+
196
+ /**
197
+ * Creates a new schema for validating boolean values.
198
+ *
199
+ * @returns {BooleanSchema} A new instance of `BooleanSchema` for validating booleans.
200
+ *
201
+ * @example
202
+ * const schema = boolean();
203
+ * parseSchema(schema, true); // Validates successfully
204
+ * parseSchema(schema, 'true'); // Throws a validation error
205
+ */
206
+ declare function boolean(): BooleanSchema;
207
+
208
+ /**
209
+ * Creates a new schema for validating arrays where each element must match the specified schema.
210
+ *
211
+ * @template T
212
+ * @param {T} arraySchema - The schema that each element of the array must match.
213
+ * @returns {WithArray<T>} A new instance of `ArraySchema` for validating arrays of elements that match the specified schema.
214
+ *
215
+ * @example
216
+ * const schema = array(string());
217
+ * parseSchema(schema, ['hello', 'world']); // Validates successfully
218
+ * parseSchema(schema, ['hello', 123]); // Throws a validation error
219
+ */
220
+ declare function array<T extends CommonSchema>(arraySchema: T): WithArray<T>;
221
+
222
+ /**
223
+ * Creates a new schema for validating objects where each property must match the specified schema.
224
+ *
225
+ * @template T
226
+ * @param {T} shapeSchema - The schema that each property of the object must match.
227
+ * @returns {WithObject<T>} A new instance of `ObjectSchema` for validating objects with properties matching the specified schema.
228
+ *
229
+ * @example
230
+ * const schema = object({
231
+ * name: string(),
232
+ * age: number()
233
+ * });
234
+ * parseSchema(schema, { name: 'John', age: 30 }); // Validates successfully
235
+ * parseSchema(schema, { name: 'John', age: '30' }); // Throws a validation error
236
+ */
237
+ declare function object<T extends ObjectShapeSchemaType>(shapeSchema: T): WithObject<T>;
238
+
239
+ /**
240
+ * Creates a new schema for validating values that can match any one of the specified primitive types.
241
+ *
242
+ * @template T
243
+ * @param {T} valueTypes - An array of primitive types that the value can match.
244
+ * @returns {WithMix<MapMixTypes<T>>} A new schema for validating values that can match any of the specified types.
245
+ *
246
+ * @example
247
+ * const schema = oneOfTypes(['string', 'number']);
248
+ * parseSchema(schema, 'hello'); // Validates successfully
249
+ * parseSchema(schema, 42); // Validates successfully
250
+ * parseSchema(schema, true); // Throws a validation error
251
+ */
252
+ declare function oneOfTypes<T extends PrimitiveType[]>(valueTypes: T): WithMix<MapMixTypes<T>>;
253
+
254
+ export { type InferType, array, boolean, number, object, oneOfTypes, parseSchema, string };
package/lib/index.d.ts ADDED
@@ -0,0 +1,254 @@
1
+ declare const ctxSymbol: unique symbol;
2
+
3
+ type RequiredValidation = (received: any, pathToError: string) => void;
4
+ type ObjectShapeSchemaType = Record<string, CommonSchema>;
5
+ type PrimitiveType = 'number' | 'string' | 'boolean' | 'undefined' | 'object' | 'function' | 'symbol' | 'bigint';
6
+ interface ValidatorContext {
7
+ type: PrimitiveType[];
8
+ isNullable?: boolean;
9
+ isOptional?: boolean;
10
+ requiredValidations: RequiredValidation[];
11
+ array?: CommonSchema;
12
+ object?: ObjectShapeSchemaType;
13
+ }
14
+ declare class CommonSchema {
15
+ [ctxSymbol]: ValidatorContext;
16
+ constructor(ctx: ValidatorContext);
17
+ /**
18
+ * @param validators - One or more custom validation functions.
19
+ * @returns {this} The schema instance with the added custom validation.
20
+ */
21
+ custom(...validators: RequiredValidation[]): this;
22
+ /**
23
+ * Marks the schema as nullable, allowing the value to be `null`.
24
+ *
25
+ * @returns {WithNull<this>} The schema instance marked as nullable.
26
+ */
27
+ nullable(): WithNull<this>;
28
+ /**
29
+ * Marks the schema as optional, allowing the value to be `undefined`.
30
+ *
31
+ * @returns {WithUndefined<this>}} The schema instance marked as optional.
32
+ */
33
+ optional(): WithUndefined<this>;
34
+ }
35
+ type WithNull<T extends CommonSchema> = T & {
36
+ validation_null: true;
37
+ };
38
+ type WithUndefined<T extends CommonSchema> = T & {
39
+ validation_undefined: true;
40
+ };
41
+ type TypeMapping = {
42
+ number: number;
43
+ string: string;
44
+ boolean: boolean;
45
+ undefined: undefined;
46
+ object: object;
47
+ function: Function;
48
+ symbol: symbol;
49
+ bigint: bigint;
50
+ };
51
+ type WithMix<Y = unknown> = CommonSchema & {
52
+ validation_mix: Y;
53
+ };
54
+ type ExtractFromMix<T> = T extends WithMix<infer X> ? X : never;
55
+ type MapMixTypes<T extends PrimitiveType[]> = T extends (infer U)[] ? U extends keyof TypeMapping ? TypeMapping[U] : never : never;
56
+
57
+ declare class ArraySchema extends CommonSchema {
58
+ _array: number;
59
+ constructor(ctx: ValidatorContext, arraySchema: CommonSchema);
60
+ private validateArrayEntry;
61
+ }
62
+ type WithArray<Y extends CommonSchema> = ArraySchema & {
63
+ validation_array: Y;
64
+ };
65
+ type ExtractFromArray<T> = T extends WithArray<infer X> ? X : never;
66
+
67
+ declare class BooleanSchema extends CommonSchema {
68
+ _boolean: number;
69
+ /**
70
+ * Restricts the schema to exactly match the boolean value true and infers the true value as the TypeScript type.
71
+ *
72
+ * @returns - The schema instance restricted to the value true, with the true value inferred as the TypeScript type
73
+ *
74
+ * @example - boolean().onlyTrue(); // Infers the type true
75
+ */
76
+ onlyTrue(): WithBoolean<this, true>;
77
+ /**
78
+ * Restricts the schema to exactly match the boolean value false and infers the false value as the TypeScript type.
79
+ *
80
+ * @returns - The schema instance restricted to the value false, with the false value inferred as the TypeScript type
81
+ *
82
+ * @example - boolean().onlyFalse(); // Infers the type false
83
+ */
84
+ onlyFalse(): WithBoolean<this, false>;
85
+ }
86
+ type WithBoolean<T extends BooleanSchema, Y = boolean> = T & {
87
+ validation_boolean: Y;
88
+ };
89
+ type ExtractFromBoolean<T> = T extends WithBoolean<BooleanSchema, infer Y> ? Y : never;
90
+
91
+ declare class NumberSchema extends CommonSchema {
92
+ _number: number;
93
+ /**
94
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
95
+ *
96
+ * @param expectedValue - The value that the schema must exactly match.
97
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
98
+ *
99
+ * @example - number().equalTo(42); // Infers the type 42
100
+ */
101
+ equalTo<Y extends number>(expectedValue: Y): WithNumber<this, Y>;
102
+ }
103
+ type WithNumber<T extends NumberSchema, Y = number> = T & {
104
+ validation_number: Y;
105
+ };
106
+ type ExtractFromNumber<T> = T extends WithNumber<NumberSchema, infer Y> ? Y : never;
107
+
108
+ declare class ObjectSchema extends CommonSchema {
109
+ _object: number;
110
+ constructor(ctx: ValidatorContext, shapeSchema: ObjectShapeSchemaType);
111
+ private validateObjectEntry;
112
+ }
113
+ type WithObject<Y extends ObjectShapeSchemaType> = ObjectSchema & {
114
+ validation_object: Y;
115
+ };
116
+
117
+ declare class StringSchema extends CommonSchema {
118
+ _string: number;
119
+ /**
120
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
121
+ *
122
+ * @param expectedValue - The value that the schema must exactly match.
123
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
124
+ *
125
+ * @example - string().equalTo('hello'); // Infers the type 'hello'
126
+ */
127
+ equalTo<Y extends string>(expectedValue: Y): WithString<this, Y>;
128
+ }
129
+ type WithString<T extends StringSchema, Y = string> = T & {
130
+ validation_string: Y;
131
+ };
132
+ type ExtractFromString<T> = T extends WithString<StringSchema, infer Y> ? Y : never;
133
+
134
+ type InferType<T> = T extends WithUndefined<WithNull<WithString<StringSchema>>> ? ExtractFromString<T> | null | undefined : T extends WithUndefined<WithString<StringSchema>> ? ExtractFromString<T> | undefined : T extends WithNull<WithString<StringSchema>> ? ExtractFromString<T> | null : T extends WithString<StringSchema> ? ExtractFromString<T> : T extends WithUndefined<WithNull<StringSchema>> ? string | null | undefined : T extends WithUndefined<StringSchema> ? string | undefined : T extends WithNull<StringSchema> ? string | null : T extends StringSchema ? string : T extends WithUndefined<WithNull<WithNumber<NumberSchema>>> ? ExtractFromNumber<T> | null | undefined : T extends WithUndefined<WithNumber<NumberSchema>> ? ExtractFromNumber<T> | undefined : T extends WithNull<WithNumber<NumberSchema>> ? ExtractFromNumber<T> | null : T extends WithNumber<NumberSchema> ? ExtractFromNumber<T> : T extends WithUndefined<WithNull<NumberSchema>> ? number | null | undefined : T extends WithUndefined<NumberSchema> ? number | undefined : T extends WithNull<NumberSchema> ? number | null : T extends NumberSchema ? number : T extends WithUndefined<WithNull<WithBoolean<BooleanSchema>>> ? ExtractFromBoolean<T> | null | undefined : T extends WithUndefined<WithBoolean<BooleanSchema>> ? ExtractFromBoolean<T> | undefined : T extends WithNull<WithBoolean<BooleanSchema>> ? ExtractFromBoolean<T> | null : T extends WithBoolean<BooleanSchema> ? ExtractFromBoolean<T> : T extends WithUndefined<WithNull<BooleanSchema>> ? boolean | null | undefined : T extends WithUndefined<BooleanSchema> ? boolean | undefined : T extends WithNull<BooleanSchema> ? boolean | null : T extends BooleanSchema ? boolean : T extends WithUndefined<WithNull<ArraySchema>> ? InferType<ExtractFromArray<T>>[] | null | undefined : T extends WithUndefined<ArraySchema> ? InferType<ExtractFromArray<T>>[] | undefined : T extends WithNull<ArraySchema> ? InferType<ExtractFromArray<T>>[] | null : T extends ArraySchema ? InferType<ExtractFromArray<T>>[] : T extends WithUndefined<WithNull<ObjectSchema>> ? ExtractFromObject<T> | null | undefined : T extends WithUndefined<ObjectSchema> ? ExtractFromObject<T> | undefined : T extends WithNull<ObjectSchema> ? ExtractFromObject<T> | null : T extends ObjectSchema ? ExtractFromObject<T> : T extends WithUndefined<WithNull<WithMix>> ? ExtractFromMix<T> | null | undefined : T extends WithUndefined<WithMix> ? ExtractFromMix<T> | undefined : T extends WithNull<WithMix> ? ExtractFromMix<T> | null : T extends WithMix ? ExtractFromMix<T> : unknown;
135
+ type Merge<T> = T extends infer U ? {
136
+ [K in keyof U]: U[K];
137
+ } : never;
138
+ type ExtractFromObject<T extends ObjectSchema> = T extends WithObject<infer X> ? Merge<{
139
+ [K in keyof X as X[K] extends WithUndefined<CommonSchema> ? never : K]: InferType<X[K]>;
140
+ } & {
141
+ [K in keyof X as X[K] extends WithUndefined<CommonSchema> ? K : never]?: InferType<X[K]>;
142
+ }> : unknown;
143
+
144
+ /**
145
+ * Parses and validates a value against the provided schema, returning a type-safe result.
146
+ *
147
+ * This function will throw a `ValidationError` if the value does not conform to the schema.
148
+ * The inferred TypeScript type of the returned value will match the structure defined by the schema.
149
+ *
150
+ * @template T
151
+ * @param {T} schema - The schema to validate the received value against. This schema dictates the expected structure and type of the value.
152
+ * @param {unknown} receivedValue - The value to be validated and parsed according to the schema.
153
+ * @returns {InferType<T>} The validated value, with its TypeScript type inferred from the schema.
154
+ *
155
+ * @throws {ValidationError} If the received value does not match the schema, a `ValidationError` will be thrown.
156
+ * @throws {Error} If an unexpected error occurs during validation, an error will be thrown with a generic message.
157
+ *
158
+ * @example
159
+ * const schema = object({
160
+ * name: string(),
161
+ * age: number(),
162
+ * });
163
+ *
164
+ * const result = parseSchema(schema, { name: 'Alice', age: 30 });
165
+ * // result will be inferred as { name: string; age: number }
166
+ *
167
+ * parseSchema(schema, { name: 'Alice', age: '30' });
168
+ * // Throws ValidationError because 'age' should be a number, not a string.
169
+ */
170
+ declare function parseSchema<T extends CommonSchema>(schema: T, receivedValue: unknown): InferType<T>;
171
+
172
+ /**
173
+ * Creates a new schema for validating number values.
174
+ *
175
+ * @returns {NumberSchema} A new instance of `NumberSchema` for validating numbers.
176
+ *
177
+ * @example
178
+ * const schema = number();
179
+ * parseSchema(schema, 42); // Validates successfully
180
+ * parseSchema(schema, '42'); // Throws a validation error
181
+ */
182
+ declare function number(): NumberSchema;
183
+
184
+ /**
185
+ * Creates a new schema for validating string values.
186
+ *
187
+ * @returns {StringSchema} A new instance of `StringSchema` for validating strings.
188
+ *
189
+ * @example
190
+ * const schema = string();
191
+ * parseSchema(schema, 'hello'); // Validates successfully
192
+ * parseSchema(schema, 123); // Throws a validation error
193
+ */
194
+ declare function string(): StringSchema;
195
+
196
+ /**
197
+ * Creates a new schema for validating boolean values.
198
+ *
199
+ * @returns {BooleanSchema} A new instance of `BooleanSchema` for validating booleans.
200
+ *
201
+ * @example
202
+ * const schema = boolean();
203
+ * parseSchema(schema, true); // Validates successfully
204
+ * parseSchema(schema, 'true'); // Throws a validation error
205
+ */
206
+ declare function boolean(): BooleanSchema;
207
+
208
+ /**
209
+ * Creates a new schema for validating arrays where each element must match the specified schema.
210
+ *
211
+ * @template T
212
+ * @param {T} arraySchema - The schema that each element of the array must match.
213
+ * @returns {WithArray<T>} A new instance of `ArraySchema` for validating arrays of elements that match the specified schema.
214
+ *
215
+ * @example
216
+ * const schema = array(string());
217
+ * parseSchema(schema, ['hello', 'world']); // Validates successfully
218
+ * parseSchema(schema, ['hello', 123]); // Throws a validation error
219
+ */
220
+ declare function array<T extends CommonSchema>(arraySchema: T): WithArray<T>;
221
+
222
+ /**
223
+ * Creates a new schema for validating objects where each property must match the specified schema.
224
+ *
225
+ * @template T
226
+ * @param {T} shapeSchema - The schema that each property of the object must match.
227
+ * @returns {WithObject<T>} A new instance of `ObjectSchema` for validating objects with properties matching the specified schema.
228
+ *
229
+ * @example
230
+ * const schema = object({
231
+ * name: string(),
232
+ * age: number()
233
+ * });
234
+ * parseSchema(schema, { name: 'John', age: 30 }); // Validates successfully
235
+ * parseSchema(schema, { name: 'John', age: '30' }); // Throws a validation error
236
+ */
237
+ declare function object<T extends ObjectShapeSchemaType>(shapeSchema: T): WithObject<T>;
238
+
239
+ /**
240
+ * Creates a new schema for validating values that can match any one of the specified primitive types.
241
+ *
242
+ * @template T
243
+ * @param {T} valueTypes - An array of primitive types that the value can match.
244
+ * @returns {WithMix<MapMixTypes<T>>} A new schema for validating values that can match any of the specified types.
245
+ *
246
+ * @example
247
+ * const schema = oneOfTypes(['string', 'number']);
248
+ * parseSchema(schema, 'hello'); // Validates successfully
249
+ * parseSchema(schema, 42); // Validates successfully
250
+ * parseSchema(schema, true); // Throws a validation error
251
+ */
252
+ declare function oneOfTypes<T extends PrimitiveType[]>(valueTypes: T): WithMix<MapMixTypes<T>>;
253
+
254
+ export { type InferType, array, boolean, number, object, oneOfTypes, parseSchema, string };
package/lib/index.js ADDED
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ array: () => array,
24
+ boolean: () => boolean,
25
+ number: () => number,
26
+ object: () => object,
27
+ oneOfTypes: () => oneOfTypes,
28
+ parseSchema: () => parseSchema,
29
+ string: () => string
30
+ });
31
+ module.exports = __toCommonJS(src_exports);
32
+
33
+ // src/exceptions.ts
34
+ var ValidationError = class extends Error {
35
+ expected;
36
+ received;
37
+ pathToError;
38
+ message;
39
+ constructor(expected, received, pathToError, message) {
40
+ super();
41
+ this.expected = expected;
42
+ this.received = received;
43
+ this.pathToError = pathToError;
44
+ this.message = message;
45
+ }
46
+ };
47
+ var BuildSchemaError = class extends Error {
48
+ };
49
+ function throwException(expected, received, pathToError, message) {
50
+ throw new ValidationError(expected, received, pathToError, message);
51
+ }
52
+
53
+ // src/core.ts
54
+ var ctxSymbol = Symbol("contextSymbol");
55
+ function innerCheck(schema, receivedValue, pathToError) {
56
+ const ctx = schema[ctxSymbol];
57
+ if (receivedValue === void 0) {
58
+ if (!ctx.isOptional) throwException("Required", receivedValue, pathToError, "The required value is missing");
59
+ return receivedValue;
60
+ }
61
+ if (receivedValue === null) {
62
+ if (!ctx.isNullable) throwException("Not null", receivedValue, pathToError, "Value should not be null");
63
+ return receivedValue;
64
+ }
65
+ if (ctx.array) {
66
+ if (!Array.isArray(receivedValue))
67
+ throwException("Array", receivedValue, pathToError, "Expected an array but received a different type");
68
+ const schema2 = ctx.array;
69
+ receivedValue.forEach((elem, i) => {
70
+ innerCheck(schema2, elem, `${pathToError}[${i}]`);
71
+ });
72
+ return receivedValue;
73
+ }
74
+ const typeOfVal = typeof receivedValue;
75
+ if (ctx.object) {
76
+ if (typeOfVal !== "object")
77
+ throwException("Object", receivedValue, pathToError, "Expected an object but received a different type");
78
+ if (Array.isArray(receivedValue))
79
+ throwException(
80
+ "Object",
81
+ receivedValue,
82
+ pathToError,
83
+ "Expected an object but received an array. Invalid type of data"
84
+ );
85
+ const shapeSchema = ctx.object;
86
+ for (const keyPerReceivedValue of Object.keys(receivedValue)) {
87
+ if (shapeSchema[keyPerReceivedValue] === void 0)
88
+ throwException("Not allowed", keyPerReceivedValue, pathToError, "This key is not allowed in the object");
89
+ }
90
+ for (const [keyOfSchema, valueOfSchema] of Object.entries(shapeSchema)) {
91
+ const receivedObjectValuePropery = receivedValue[keyOfSchema];
92
+ if (receivedObjectValuePropery === void 0) {
93
+ if (!valueOfSchema[ctxSymbol].isOptional)
94
+ throwException(
95
+ "Required",
96
+ receivedObjectValuePropery,
97
+ pathToError,
98
+ "Missing required property in the object"
99
+ );
100
+ }
101
+ innerCheck(valueOfSchema, receivedObjectValuePropery, `${pathToError}.${keyOfSchema}`);
102
+ }
103
+ return receivedValue;
104
+ }
105
+ if (ctx.type.length) {
106
+ if (!ctx.type.includes(typeOfVal)) throwException(ctx.type, typeOfVal, pathToError, "Invalid type of data");
107
+ }
108
+ ctx.requiredValidations.forEach((requiredValidation) => {
109
+ requiredValidation(receivedValue, pathToError);
110
+ });
111
+ return receivedValue;
112
+ }
113
+
114
+ // src/parseSchema.ts
115
+ function parseSchema(schema, receivedValue) {
116
+ try {
117
+ return innerCheck(schema, receivedValue, "");
118
+ } catch (e) {
119
+ if (e instanceof ValidationError) throw e;
120
+ throw new Error("Something unexpected happened");
121
+ }
122
+ }
123
+
124
+ // src/asserts/common/equalTo.ts
125
+ var equalTo = (expected) => (received, pathToError) => {
126
+ if (expected !== received)
127
+ throwException(expected, received, pathToError, "The received value is not equal to expected");
128
+ };
129
+
130
+ // src/schemas/CommonSchema.ts
131
+ var CommonSchema = class {
132
+ [ctxSymbol];
133
+ constructor(ctx) {
134
+ this[ctxSymbol] = ctx;
135
+ }
136
+ /**
137
+ * @param validators - One or more custom validation functions.
138
+ * @returns {this} The schema instance with the added custom validation.
139
+ */
140
+ custom(...validators) {
141
+ this[ctxSymbol].requiredValidations.push(...validators);
142
+ return this;
143
+ }
144
+ /**
145
+ * Marks the schema as nullable, allowing the value to be `null`.
146
+ *
147
+ * @returns {WithNull<this>} The schema instance marked as nullable.
148
+ */
149
+ nullable() {
150
+ this[ctxSymbol].isNullable = true;
151
+ return this;
152
+ }
153
+ /**
154
+ * Marks the schema as optional, allowing the value to be `undefined`.
155
+ *
156
+ * @returns {WithUndefined<this>}} The schema instance marked as optional.
157
+ */
158
+ optional() {
159
+ this[ctxSymbol].isOptional = true;
160
+ return this;
161
+ }
162
+ };
163
+
164
+ // src/schemas/NumberSchema.ts
165
+ var NumberSchema = class extends CommonSchema {
166
+ _number = 1;
167
+ /**
168
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
169
+ *
170
+ * @param expectedValue - The value that the schema must exactly match.
171
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
172
+ *
173
+ * @example - number().equalTo(42); // Infers the type 42
174
+ */
175
+ equalTo(expectedValue) {
176
+ return this.custom(equalTo(expectedValue));
177
+ }
178
+ };
179
+
180
+ // src/asserts/number/index.ts
181
+ function number() {
182
+ return new NumberSchema({ type: ["number"], requiredValidations: [] });
183
+ }
184
+
185
+ // src/schemas/StringSchema.ts
186
+ var StringSchema = class extends CommonSchema {
187
+ _string = 1;
188
+ /**
189
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
190
+ *
191
+ * @param expectedValue - The value that the schema must exactly match.
192
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
193
+ *
194
+ * @example - string().equalTo('hello'); // Infers the type 'hello'
195
+ */
196
+ equalTo(expectedValue) {
197
+ return this.custom(equalTo(expectedValue));
198
+ }
199
+ };
200
+
201
+ // src/asserts/string/index.ts
202
+ function string() {
203
+ return new StringSchema({ type: ["string"], requiredValidations: [] });
204
+ }
205
+
206
+ // src/schemas/BooleanSchema.ts
207
+ var isBoolean = (expected) => (received, pathToError) => {
208
+ if (received !== expected) throwException(expected, received, pathToError, `The received value is not ${expected}`);
209
+ };
210
+ var BooleanSchema = class extends CommonSchema {
211
+ _boolean = 1;
212
+ /**
213
+ * Restricts the schema to exactly match the boolean value true and infers the true value as the TypeScript type.
214
+ *
215
+ * @returns - The schema instance restricted to the value true, with the true value inferred as the TypeScript type
216
+ *
217
+ * @example - boolean().onlyTrue(); // Infers the type true
218
+ */
219
+ onlyTrue() {
220
+ return this.custom(isBoolean(true));
221
+ }
222
+ /**
223
+ * Restricts the schema to exactly match the boolean value false and infers the false value as the TypeScript type.
224
+ *
225
+ * @returns - The schema instance restricted to the value false, with the false value inferred as the TypeScript type
226
+ *
227
+ * @example - boolean().onlyFalse(); // Infers the type false
228
+ */
229
+ onlyFalse() {
230
+ return this.custom(isBoolean(false));
231
+ }
232
+ };
233
+
234
+ // src/asserts/boolean/index.ts
235
+ function boolean() {
236
+ return new BooleanSchema({ type: ["boolean"], requiredValidations: [] });
237
+ }
238
+
239
+ // src/schemas/ArraySchema.ts
240
+ var ArraySchema = class extends CommonSchema {
241
+ _array = 1;
242
+ constructor(ctx, arraySchema) {
243
+ super(ctx);
244
+ this.validateArrayEntry(arraySchema);
245
+ this[ctxSymbol].array = arraySchema;
246
+ }
247
+ validateArrayEntry(arraySchema) {
248
+ if (!arraySchema) throw new BuildSchemaError("Missing schema in array method");
249
+ if (!(arraySchema instanceof CommonSchema)) throw new BuildSchemaError("Invalid schema in array method");
250
+ }
251
+ };
252
+
253
+ // src/asserts/array/index.ts
254
+ function array(arraySchema) {
255
+ return new ArraySchema({ type: [], requiredValidations: [] }, arraySchema);
256
+ }
257
+
258
+ // src/schemas/ObjectSchema.ts
259
+ var ObjectSchema = class extends CommonSchema {
260
+ _object = 1;
261
+ constructor(ctx, shapeSchema) {
262
+ super(ctx);
263
+ this.validateObjectEntry(shapeSchema);
264
+ this[ctxSymbol].object = shapeSchema;
265
+ }
266
+ validateObjectEntry(shapeSchema) {
267
+ if (!shapeSchema) throw new BuildSchemaError("Missing schema in object method");
268
+ if (shapeSchema instanceof CommonSchema) throw new BuildSchemaError("Invalid schema in object");
269
+ for (const [key, value] of Object.entries(shapeSchema)) {
270
+ if (!(value instanceof CommonSchema))
271
+ throw new BuildSchemaError(`Invalid schema in object method for property '${key}'`);
272
+ }
273
+ }
274
+ };
275
+
276
+ // src/asserts/object/index.ts
277
+ function object(shapeSchema) {
278
+ return new ObjectSchema({ type: [], requiredValidations: [] }, shapeSchema);
279
+ }
280
+
281
+ // src/asserts/common/index.ts
282
+ function oneOfTypes(valueTypes) {
283
+ return new CommonSchema({ type: valueTypes, requiredValidations: [] });
284
+ }
285
+ // Annotate the CommonJS export names for ESM import in node:
286
+ 0 && (module.exports = {
287
+ array,
288
+ boolean,
289
+ number,
290
+ object,
291
+ oneOfTypes,
292
+ parseSchema,
293
+ string
294
+ });
package/lib/index.mjs ADDED
@@ -0,0 +1,261 @@
1
+ // src/exceptions.ts
2
+ var ValidationError = class extends Error {
3
+ expected;
4
+ received;
5
+ pathToError;
6
+ message;
7
+ constructor(expected, received, pathToError, message) {
8
+ super();
9
+ this.expected = expected;
10
+ this.received = received;
11
+ this.pathToError = pathToError;
12
+ this.message = message;
13
+ }
14
+ };
15
+ var BuildSchemaError = class extends Error {
16
+ };
17
+ function throwException(expected, received, pathToError, message) {
18
+ throw new ValidationError(expected, received, pathToError, message);
19
+ }
20
+
21
+ // src/core.ts
22
+ var ctxSymbol = Symbol("contextSymbol");
23
+ function innerCheck(schema, receivedValue, pathToError) {
24
+ const ctx = schema[ctxSymbol];
25
+ if (receivedValue === void 0) {
26
+ if (!ctx.isOptional) throwException("Required", receivedValue, pathToError, "The required value is missing");
27
+ return receivedValue;
28
+ }
29
+ if (receivedValue === null) {
30
+ if (!ctx.isNullable) throwException("Not null", receivedValue, pathToError, "Value should not be null");
31
+ return receivedValue;
32
+ }
33
+ if (ctx.array) {
34
+ if (!Array.isArray(receivedValue))
35
+ throwException("Array", receivedValue, pathToError, "Expected an array but received a different type");
36
+ const schema2 = ctx.array;
37
+ receivedValue.forEach((elem, i) => {
38
+ innerCheck(schema2, elem, `${pathToError}[${i}]`);
39
+ });
40
+ return receivedValue;
41
+ }
42
+ const typeOfVal = typeof receivedValue;
43
+ if (ctx.object) {
44
+ if (typeOfVal !== "object")
45
+ throwException("Object", receivedValue, pathToError, "Expected an object but received a different type");
46
+ if (Array.isArray(receivedValue))
47
+ throwException(
48
+ "Object",
49
+ receivedValue,
50
+ pathToError,
51
+ "Expected an object but received an array. Invalid type of data"
52
+ );
53
+ const shapeSchema = ctx.object;
54
+ for (const keyPerReceivedValue of Object.keys(receivedValue)) {
55
+ if (shapeSchema[keyPerReceivedValue] === void 0)
56
+ throwException("Not allowed", keyPerReceivedValue, pathToError, "This key is not allowed in the object");
57
+ }
58
+ for (const [keyOfSchema, valueOfSchema] of Object.entries(shapeSchema)) {
59
+ const receivedObjectValuePropery = receivedValue[keyOfSchema];
60
+ if (receivedObjectValuePropery === void 0) {
61
+ if (!valueOfSchema[ctxSymbol].isOptional)
62
+ throwException(
63
+ "Required",
64
+ receivedObjectValuePropery,
65
+ pathToError,
66
+ "Missing required property in the object"
67
+ );
68
+ }
69
+ innerCheck(valueOfSchema, receivedObjectValuePropery, `${pathToError}.${keyOfSchema}`);
70
+ }
71
+ return receivedValue;
72
+ }
73
+ if (ctx.type.length) {
74
+ if (!ctx.type.includes(typeOfVal)) throwException(ctx.type, typeOfVal, pathToError, "Invalid type of data");
75
+ }
76
+ ctx.requiredValidations.forEach((requiredValidation) => {
77
+ requiredValidation(receivedValue, pathToError);
78
+ });
79
+ return receivedValue;
80
+ }
81
+
82
+ // src/parseSchema.ts
83
+ function parseSchema(schema, receivedValue) {
84
+ try {
85
+ return innerCheck(schema, receivedValue, "");
86
+ } catch (e) {
87
+ if (e instanceof ValidationError) throw e;
88
+ throw new Error("Something unexpected happened");
89
+ }
90
+ }
91
+
92
+ // src/asserts/common/equalTo.ts
93
+ var equalTo = (expected) => (received, pathToError) => {
94
+ if (expected !== received)
95
+ throwException(expected, received, pathToError, "The received value is not equal to expected");
96
+ };
97
+
98
+ // src/schemas/CommonSchema.ts
99
+ var CommonSchema = class {
100
+ [ctxSymbol];
101
+ constructor(ctx) {
102
+ this[ctxSymbol] = ctx;
103
+ }
104
+ /**
105
+ * @param validators - One or more custom validation functions.
106
+ * @returns {this} The schema instance with the added custom validation.
107
+ */
108
+ custom(...validators) {
109
+ this[ctxSymbol].requiredValidations.push(...validators);
110
+ return this;
111
+ }
112
+ /**
113
+ * Marks the schema as nullable, allowing the value to be `null`.
114
+ *
115
+ * @returns {WithNull<this>} The schema instance marked as nullable.
116
+ */
117
+ nullable() {
118
+ this[ctxSymbol].isNullable = true;
119
+ return this;
120
+ }
121
+ /**
122
+ * Marks the schema as optional, allowing the value to be `undefined`.
123
+ *
124
+ * @returns {WithUndefined<this>}} The schema instance marked as optional.
125
+ */
126
+ optional() {
127
+ this[ctxSymbol].isOptional = true;
128
+ return this;
129
+ }
130
+ };
131
+
132
+ // src/schemas/NumberSchema.ts
133
+ var NumberSchema = class extends CommonSchema {
134
+ _number = 1;
135
+ /**
136
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
137
+ *
138
+ * @param expectedValue - The value that the schema must exactly match.
139
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
140
+ *
141
+ * @example - number().equalTo(42); // Infers the type 42
142
+ */
143
+ equalTo(expectedValue) {
144
+ return this.custom(equalTo(expectedValue));
145
+ }
146
+ };
147
+
148
+ // src/asserts/number/index.ts
149
+ function number() {
150
+ return new NumberSchema({ type: ["number"], requiredValidations: [] });
151
+ }
152
+
153
+ // src/schemas/StringSchema.ts
154
+ var StringSchema = class extends CommonSchema {
155
+ _string = 1;
156
+ /**
157
+ * Restricts the schema to exactly match the specified value and infers the literal value as the TypeScript type.
158
+ *
159
+ * @param expectedValue - The value that the schema must exactly match.
160
+ * @returns - The schema instance restricted to the specified value, with the literal value inferred as the TypeScript type
161
+ *
162
+ * @example - string().equalTo('hello'); // Infers the type 'hello'
163
+ */
164
+ equalTo(expectedValue) {
165
+ return this.custom(equalTo(expectedValue));
166
+ }
167
+ };
168
+
169
+ // src/asserts/string/index.ts
170
+ function string() {
171
+ return new StringSchema({ type: ["string"], requiredValidations: [] });
172
+ }
173
+
174
+ // src/schemas/BooleanSchema.ts
175
+ var isBoolean = (expected) => (received, pathToError) => {
176
+ if (received !== expected) throwException(expected, received, pathToError, `The received value is not ${expected}`);
177
+ };
178
+ var BooleanSchema = class extends CommonSchema {
179
+ _boolean = 1;
180
+ /**
181
+ * Restricts the schema to exactly match the boolean value true and infers the true value as the TypeScript type.
182
+ *
183
+ * @returns - The schema instance restricted to the value true, with the true value inferred as the TypeScript type
184
+ *
185
+ * @example - boolean().onlyTrue(); // Infers the type true
186
+ */
187
+ onlyTrue() {
188
+ return this.custom(isBoolean(true));
189
+ }
190
+ /**
191
+ * Restricts the schema to exactly match the boolean value false and infers the false value as the TypeScript type.
192
+ *
193
+ * @returns - The schema instance restricted to the value false, with the false value inferred as the TypeScript type
194
+ *
195
+ * @example - boolean().onlyFalse(); // Infers the type false
196
+ */
197
+ onlyFalse() {
198
+ return this.custom(isBoolean(false));
199
+ }
200
+ };
201
+
202
+ // src/asserts/boolean/index.ts
203
+ function boolean() {
204
+ return new BooleanSchema({ type: ["boolean"], requiredValidations: [] });
205
+ }
206
+
207
+ // src/schemas/ArraySchema.ts
208
+ var ArraySchema = class extends CommonSchema {
209
+ _array = 1;
210
+ constructor(ctx, arraySchema) {
211
+ super(ctx);
212
+ this.validateArrayEntry(arraySchema);
213
+ this[ctxSymbol].array = arraySchema;
214
+ }
215
+ validateArrayEntry(arraySchema) {
216
+ if (!arraySchema) throw new BuildSchemaError("Missing schema in array method");
217
+ if (!(arraySchema instanceof CommonSchema)) throw new BuildSchemaError("Invalid schema in array method");
218
+ }
219
+ };
220
+
221
+ // src/asserts/array/index.ts
222
+ function array(arraySchema) {
223
+ return new ArraySchema({ type: [], requiredValidations: [] }, arraySchema);
224
+ }
225
+
226
+ // src/schemas/ObjectSchema.ts
227
+ var ObjectSchema = class extends CommonSchema {
228
+ _object = 1;
229
+ constructor(ctx, shapeSchema) {
230
+ super(ctx);
231
+ this.validateObjectEntry(shapeSchema);
232
+ this[ctxSymbol].object = shapeSchema;
233
+ }
234
+ validateObjectEntry(shapeSchema) {
235
+ if (!shapeSchema) throw new BuildSchemaError("Missing schema in object method");
236
+ if (shapeSchema instanceof CommonSchema) throw new BuildSchemaError("Invalid schema in object");
237
+ for (const [key, value] of Object.entries(shapeSchema)) {
238
+ if (!(value instanceof CommonSchema))
239
+ throw new BuildSchemaError(`Invalid schema in object method for property '${key}'`);
240
+ }
241
+ }
242
+ };
243
+
244
+ // src/asserts/object/index.ts
245
+ function object(shapeSchema) {
246
+ return new ObjectSchema({ type: [], requiredValidations: [] }, shapeSchema);
247
+ }
248
+
249
+ // src/asserts/common/index.ts
250
+ function oneOfTypes(valueTypes) {
251
+ return new CommonSchema({ type: valueTypes, requiredValidations: [] });
252
+ }
253
+ export {
254
+ array,
255
+ boolean,
256
+ number,
257
+ object,
258
+ oneOfTypes,
259
+ parseSchema,
260
+ string
261
+ };
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "bguard",
3
+ "private": false,
4
+ "license": "MIT",
5
+ "version": "0.0.1",
6
+ "main": "lib/index.js",
7
+ "module": "lib/index.mjs",
8
+ "types": "lib/index.d.ts",
9
+ "files": [
10
+ "/lib"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/NBlasko/bguard.git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/NBlasko/bguard/issues"
18
+ },
19
+ "keywords": [
20
+ "typescript",
21
+ "validation",
22
+ "schema",
23
+ "validators",
24
+ "type-safety",
25
+ "data-validation",
26
+ "custom-validators",
27
+ "input-validation",
28
+ "type-inference",
29
+ "bguard",
30
+ "assertions",
31
+ "data-schemas",
32
+ "runtime-validation",
33
+ "type-checking",
34
+ "typescript-schema"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "build:package": "tsup src/index.ts --format cjs,esm --dts --out-dir ./lib",
39
+ "watch": "tsc -w",
40
+ "start": "node build/src/index.js",
41
+ "test": "jest --config=./jest/config.ts",
42
+ "test:watch": "jest --watch --config=./jest/config.ts",
43
+ "test:coverage": "jest --watchAll=false --runInBand --config=./jest/config.ts --coverage",
44
+ "lint": "eslint \"src/**/*.ts\"",
45
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
46
+ "prettier": "prettier --check src",
47
+ "prettier:fix": "prettier --write src",
48
+ "lint:check": "npm run prettier && npm run lint",
49
+ "release:package": "npm run build:package && changeset publish",
50
+ "change:start": "changeset",
51
+ "change:version": "changeset version",
52
+ "change:publish": "changeset publish"
53
+ },
54
+ "devDependencies": {
55
+ "@changesets/cli": "^2.27.7",
56
+ "@eslint/eslintrc": "^3.1.0",
57
+ "@eslint/js": "^9.8.0",
58
+ "@types/jest": "^29.5.12",
59
+ "@types/node": "^22.1.0",
60
+ "@typescript-eslint/eslint-plugin": "^8.0.1",
61
+ "@typescript-eslint/parser": "^8.0.1",
62
+ "eslint": "^9.8.0",
63
+ "eslint-config-prettier": "^9.1.0",
64
+ "eslint-plugin-jest": "^28.8.0",
65
+ "globals": "^15.9.0",
66
+ "jest": "^29.7.0",
67
+ "prettier": "^3.3.3",
68
+ "ts-jest": "^29.2.4",
69
+ "ts-node": "^10.9.2",
70
+ "tsup": "^8.2.4",
71
+ "typescript": "^5.5.4"
72
+ }
73
+ }