lightv-schema 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 +21 -0
- package/README.md +100 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +367 -0
- package/dist/result.d.ts +13 -0
- package/dist/schema.d.ts +87 -0
- package/dist/transformers.d.ts +4 -0
- package/dist/types.d.ts +12 -0
- package/dist/utils.d.ts +7 -0
- package/dist/validators.d.ts +4 -0
- package/package.json +34 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Danil Yeremenchuk
|
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,100 @@
|
|
1
|
+
# LightvSchema
|
2
|
+
|
3
|
+
LightvSchema is a lightweight schema validation library for TypeScript. It provides a simple and efficient way to validate data structures.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Lightweight: Minimal footprint with no external dependencies.
|
8
|
+
- Type-safe: Leverages TypeScript's type system for compile-time validation.
|
9
|
+
- Flexible: Supports custom validation functions and error messages.
|
10
|
+
- Extensible: Easily extendable to accommodate new validation rules.
|
11
|
+
|
12
|
+
## Warning
|
13
|
+
|
14
|
+
This library is my educational project. It is not intended for production use. Use at your own risk.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
You can install LightvSchema using npm or bun:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
npm install lightv-schema
|
22
|
+
```
|
23
|
+
|
24
|
+
or
|
25
|
+
|
26
|
+
```bash
|
27
|
+
bun add lightv-schema
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
LightvSchema provides a simple API for defining and validating data structures. Here's a quick example:
|
33
|
+
|
34
|
+
```typescript
|
35
|
+
import { type, transform, validate, parse } from "lightv-schema";
|
36
|
+
|
37
|
+
const User = type.Object({
|
38
|
+
id: type.Int(),
|
39
|
+
name: validate.Min(type.String(), 5),
|
40
|
+
email: type.String(),
|
41
|
+
age: transform.ToInt(type.String()),
|
42
|
+
isActive: type.Boolean(),
|
43
|
+
friends: type.Array(type.Object({ id: type.Int(), name: type.String() })),
|
44
|
+
role: type.Union([type.Literal("admin"), type.Literal("user")]),
|
45
|
+
});
|
46
|
+
|
47
|
+
type User = typeof User.infer;
|
48
|
+
|
49
|
+
const userString = `{
|
50
|
+
"id": 1,
|
51
|
+
"name": "John Doe",
|
52
|
+
"email": "test@some.com",
|
53
|
+
"age": "123",
|
54
|
+
"isActive": true,
|
55
|
+
"friends": [
|
56
|
+
{ "id": 2, "name": "Jane Doe" },
|
57
|
+
{ "id": 3, "name": "Jack Doe" }
|
58
|
+
],
|
59
|
+
"role": "admin"
|
60
|
+
}`;
|
61
|
+
const result = parse(User, JSON.parse(userString));
|
62
|
+
|
63
|
+
if ("success" in result) {
|
64
|
+
console.log("Parsed user:", result.success);
|
65
|
+
} else {
|
66
|
+
console.log("Failed to parse user:", result.failure);
|
67
|
+
}
|
68
|
+
|
69
|
+
export { type, transform, validate, parse };
|
70
|
+
```
|
71
|
+
|
72
|
+
Also easy to extend:
|
73
|
+
|
74
|
+
```typescript
|
75
|
+
import type { Scheme } from "lightv-schema/scheme";
|
76
|
+
import { validate } from "lightv-schema";
|
77
|
+
|
78
|
+
export function Min<const Item extends Scheme>(
|
79
|
+
item: Item,
|
80
|
+
min: number,
|
81
|
+
message?: string
|
82
|
+
) {
|
83
|
+
return validate.Validator(item, (value) => {
|
84
|
+
if (typeof value === "number" && value < min) {
|
85
|
+
return {
|
86
|
+
failure: [message ?? `Number must be greater than or equal to ${min}`],
|
87
|
+
};
|
88
|
+
} else if (typeof value === "string" && value.length < min) {
|
89
|
+
return {
|
90
|
+
failure: [message ?? `String must be at least ${min} characters long`],
|
91
|
+
};
|
92
|
+
} else if (Array.isArray(value) && value.length < min) {
|
93
|
+
return {
|
94
|
+
failure: [message ?? `Array must have at least ${min} elements`],
|
95
|
+
};
|
96
|
+
}
|
97
|
+
return { success: value };
|
98
|
+
});
|
99
|
+
}
|
100
|
+
```
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
@@ -0,0 +1,367 @@
|
|
1
|
+
var __defProp = Object.defineProperty;
|
2
|
+
var __export = (target, all) => {
|
3
|
+
for (var name in all)
|
4
|
+
__defProp(target, name, {
|
5
|
+
get: all[name],
|
6
|
+
enumerable: true,
|
7
|
+
configurable: true,
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
9
|
+
});
|
10
|
+
};
|
11
|
+
|
12
|
+
// src/types.ts
|
13
|
+
var exports_types = {};
|
14
|
+
__export(exports_types, {
|
15
|
+
Union: () => Union,
|
16
|
+
Tuple: () => Tuple,
|
17
|
+
String: () => String,
|
18
|
+
Object: () => Object2,
|
19
|
+
Nullable: () => Nullable,
|
20
|
+
None: () => None,
|
21
|
+
Literal: () => Literal,
|
22
|
+
Int: () => Int,
|
23
|
+
Float: () => Float,
|
24
|
+
Boolean: () => Boolean,
|
25
|
+
Array: () => Array2
|
26
|
+
});
|
27
|
+
function Literal(literal, message) {
|
28
|
+
return {
|
29
|
+
type: "literal",
|
30
|
+
literal,
|
31
|
+
message
|
32
|
+
};
|
33
|
+
}
|
34
|
+
function None() {
|
35
|
+
return {
|
36
|
+
type: "none"
|
37
|
+
};
|
38
|
+
}
|
39
|
+
function Int(message) {
|
40
|
+
return {
|
41
|
+
type: "int",
|
42
|
+
message
|
43
|
+
};
|
44
|
+
}
|
45
|
+
function Float(message) {
|
46
|
+
return {
|
47
|
+
type: "float",
|
48
|
+
message
|
49
|
+
};
|
50
|
+
}
|
51
|
+
function String(message) {
|
52
|
+
return {
|
53
|
+
type: "string",
|
54
|
+
message
|
55
|
+
};
|
56
|
+
}
|
57
|
+
function Boolean(message) {
|
58
|
+
return {
|
59
|
+
type: "boolean",
|
60
|
+
message
|
61
|
+
};
|
62
|
+
}
|
63
|
+
function Array2(item, message) {
|
64
|
+
return {
|
65
|
+
type: "array",
|
66
|
+
item,
|
67
|
+
message
|
68
|
+
};
|
69
|
+
}
|
70
|
+
function Union(items, message) {
|
71
|
+
return {
|
72
|
+
type: "union",
|
73
|
+
items,
|
74
|
+
message
|
75
|
+
};
|
76
|
+
}
|
77
|
+
function Tuple(items, message) {
|
78
|
+
return {
|
79
|
+
type: "tuple",
|
80
|
+
items,
|
81
|
+
message
|
82
|
+
};
|
83
|
+
}
|
84
|
+
function Object2(props, message) {
|
85
|
+
return {
|
86
|
+
type: "object",
|
87
|
+
props,
|
88
|
+
message
|
89
|
+
};
|
90
|
+
}
|
91
|
+
function Nullable(item, message) {
|
92
|
+
return {
|
93
|
+
type: "nullable",
|
94
|
+
item,
|
95
|
+
message
|
96
|
+
};
|
97
|
+
}
|
98
|
+
|
99
|
+
// src/transformers.ts
|
100
|
+
var exports_transformers = {};
|
101
|
+
__export(exports_transformers, {
|
102
|
+
Transformer: () => Transformer,
|
103
|
+
ToString: () => ToString,
|
104
|
+
ToInt: () => ToInt
|
105
|
+
});
|
106
|
+
function Transformer(from, to, transformer) {
|
107
|
+
return {
|
108
|
+
type: "transform",
|
109
|
+
from,
|
110
|
+
to,
|
111
|
+
transformer
|
112
|
+
};
|
113
|
+
}
|
114
|
+
function ToString(from, message) {
|
115
|
+
return Transformer(from, String(), (value) => {
|
116
|
+
if (value === null || value === undefined) {
|
117
|
+
return { success: "" };
|
118
|
+
}
|
119
|
+
return { success: value.toString() };
|
120
|
+
});
|
121
|
+
}
|
122
|
+
function ToInt(from, message) {
|
123
|
+
return Transformer(from, Int(), (value) => {
|
124
|
+
if (value === null || value === undefined) {
|
125
|
+
return { failure: [message ?? `Expected integer`] };
|
126
|
+
}
|
127
|
+
if (typeof value === "number") {
|
128
|
+
return { success: Math.floor(value) };
|
129
|
+
} else if (typeof value === "string") {
|
130
|
+
const parsed = parseInt(value, 10);
|
131
|
+
if (isNaN(parsed)) {
|
132
|
+
return { failure: [message ?? `Expected integer`] };
|
133
|
+
}
|
134
|
+
return { success: parsed };
|
135
|
+
}
|
136
|
+
return { failure: [message ?? `Expected integer`] };
|
137
|
+
});
|
138
|
+
}
|
139
|
+
|
140
|
+
// src/validators.ts
|
141
|
+
var exports_validators = {};
|
142
|
+
__export(exports_validators, {
|
143
|
+
Validator: () => Validator,
|
144
|
+
Min: () => Min,
|
145
|
+
Max: () => Max
|
146
|
+
});
|
147
|
+
function Validator(item, validator) {
|
148
|
+
return {
|
149
|
+
type: "validation",
|
150
|
+
item,
|
151
|
+
validator
|
152
|
+
};
|
153
|
+
}
|
154
|
+
function Min(item, min, message) {
|
155
|
+
return Validator(item, (value) => {
|
156
|
+
if (typeof value === "number" && value < min) {
|
157
|
+
return {
|
158
|
+
failure: [message ?? `Number must be greater than or equal to ${min}`]
|
159
|
+
};
|
160
|
+
} else if (typeof value === "string" && value.length < min) {
|
161
|
+
return {
|
162
|
+
failure: [message ?? `String must be at least ${min} characters long`]
|
163
|
+
};
|
164
|
+
} else if (Array.isArray(value) && value.length < min) {
|
165
|
+
return {
|
166
|
+
failure: [message ?? `Array must have at least ${min} elements`]
|
167
|
+
};
|
168
|
+
}
|
169
|
+
return { success: value };
|
170
|
+
});
|
171
|
+
}
|
172
|
+
function Max(item, max, message) {
|
173
|
+
return Validator(item, (value) => {
|
174
|
+
if (typeof value === "number" && value > max) {
|
175
|
+
return {
|
176
|
+
failure: [message ?? `Number must be less than or equal to ${max}`]
|
177
|
+
};
|
178
|
+
} else if (typeof value === "string" && value.length > max) {
|
179
|
+
return {
|
180
|
+
failure: [message ?? `String must be at most ${max} characters long`]
|
181
|
+
};
|
182
|
+
} else if (Array.isArray(value) && value.length > max) {
|
183
|
+
return {
|
184
|
+
failure: [message ?? `Array must have at most ${max} elements`]
|
185
|
+
};
|
186
|
+
}
|
187
|
+
return { success: value };
|
188
|
+
});
|
189
|
+
}
|
190
|
+
|
191
|
+
// src/result.ts
|
192
|
+
function isSuccess(result) {
|
193
|
+
return "success" in result;
|
194
|
+
}
|
195
|
+
function isFailure(result) {
|
196
|
+
return "failure" in result;
|
197
|
+
}
|
198
|
+
|
199
|
+
// src/utils.ts
|
200
|
+
function parse(schema, value) {
|
201
|
+
if (schema.type === "literal") {
|
202
|
+
if (value !== schema.literal) {
|
203
|
+
return {
|
204
|
+
failure: [
|
205
|
+
schema.message ?? `Expected ${schema.literal}`
|
206
|
+
]
|
207
|
+
};
|
208
|
+
}
|
209
|
+
return { success: schema.literal };
|
210
|
+
} else if (schema.type === "none") {
|
211
|
+
if (value !== null && value !== undefined) {
|
212
|
+
return {
|
213
|
+
failure: [
|
214
|
+
schema.message ?? `Expected null or undefined`
|
215
|
+
]
|
216
|
+
};
|
217
|
+
}
|
218
|
+
} else if (schema.type === "int") {
|
219
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
220
|
+
return {
|
221
|
+
failure: [schema.message ?? `Expected integer`]
|
222
|
+
};
|
223
|
+
}
|
224
|
+
return { success: value };
|
225
|
+
} else if (schema.type === "float") {
|
226
|
+
if (typeof value !== "number") {
|
227
|
+
return {
|
228
|
+
failure: [schema.message ?? `Expected float`]
|
229
|
+
};
|
230
|
+
}
|
231
|
+
return { success: value };
|
232
|
+
} else if (schema.type === "string") {
|
233
|
+
if (typeof value !== "string") {
|
234
|
+
return {
|
235
|
+
failure: [schema.message ?? `Expected string`]
|
236
|
+
};
|
237
|
+
}
|
238
|
+
return { success: value };
|
239
|
+
} else if (schema.type === "boolean") {
|
240
|
+
if (typeof value !== "boolean") {
|
241
|
+
return {
|
242
|
+
failure: [schema.message ?? `Expected boolean`]
|
243
|
+
};
|
244
|
+
}
|
245
|
+
return { success: value };
|
246
|
+
} else if (schema.type === "array") {
|
247
|
+
if (!Array.isArray(value)) {
|
248
|
+
return {
|
249
|
+
failure: [schema.message ?? `Expected array`]
|
250
|
+
};
|
251
|
+
}
|
252
|
+
const results = value.map((item) => parse(schema.item, item));
|
253
|
+
const failures = results.filter(isFailure);
|
254
|
+
if (failures.length > 0) {
|
255
|
+
return {
|
256
|
+
failure: failures.map((result) => result.failure).flat()
|
257
|
+
};
|
258
|
+
}
|
259
|
+
return {
|
260
|
+
success: results.filter(isSuccess).map((result) => result.success)
|
261
|
+
};
|
262
|
+
} else if (schema.type === "tuple") {
|
263
|
+
if (!Array.isArray(value)) {
|
264
|
+
return {
|
265
|
+
failure: [schema.message ?? `Expected tuple`]
|
266
|
+
};
|
267
|
+
}
|
268
|
+
if (value.length !== schema.items.length) {
|
269
|
+
return {
|
270
|
+
failure: [
|
271
|
+
schema.message ?? `Expected tuple of length ${schema.items.length}`
|
272
|
+
]
|
273
|
+
};
|
274
|
+
}
|
275
|
+
const results = value.map((item, index) => parse(schema.items[index], item));
|
276
|
+
const failures = results.filter(isFailure);
|
277
|
+
if (failures.length > 0) {
|
278
|
+
return {
|
279
|
+
failure: failures.map((result) => result.failure).flat()
|
280
|
+
};
|
281
|
+
}
|
282
|
+
return {
|
283
|
+
success: results.filter((result) => ("success" in result)).map((result) => result.success)
|
284
|
+
};
|
285
|
+
} else if (schema.type === "union") {
|
286
|
+
const results = schema.items.map((item) => parse(item, value));
|
287
|
+
const failures = results.filter(isFailure);
|
288
|
+
if (failures.length === schema.items.length) {
|
289
|
+
return {
|
290
|
+
failure: failures.map((result) => result.failure).flat()
|
291
|
+
};
|
292
|
+
}
|
293
|
+
const successes = results.filter(isSuccess);
|
294
|
+
if (successes.length > 0) {
|
295
|
+
return {
|
296
|
+
success: successes[0].success
|
297
|
+
};
|
298
|
+
}
|
299
|
+
return {
|
300
|
+
failure: [
|
301
|
+
schema.message ?? `Expected one of ${schema.items.map((item) => item.type)}`
|
302
|
+
]
|
303
|
+
};
|
304
|
+
} else if (schema.type === "object") {
|
305
|
+
if (typeof value !== "object" || value === null || value === undefined) {
|
306
|
+
return {
|
307
|
+
failure: [schema.message ?? `Expected object`]
|
308
|
+
};
|
309
|
+
}
|
310
|
+
const results = Object.entries(schema.props).map(([key, item]) => [key, parse(item, value[key])]);
|
311
|
+
const failureValues = {};
|
312
|
+
const successValues = {};
|
313
|
+
for (const [key, result] of results) {
|
314
|
+
if (isFailure(result)) {
|
315
|
+
failureValues[key] = result.failure;
|
316
|
+
} else {
|
317
|
+
successValues[key] = result.success;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
if (Object.keys(failureValues).length > 0) {
|
321
|
+
return {
|
322
|
+
failure: failureValues
|
323
|
+
};
|
324
|
+
}
|
325
|
+
return { success: successValues };
|
326
|
+
} else if (schema.type === "validation") {
|
327
|
+
const result = parse(schema.item, value);
|
328
|
+
if (isFailure(result)) {
|
329
|
+
return result;
|
330
|
+
}
|
331
|
+
const validationResult = schema.validator(result.success);
|
332
|
+
if (isFailure(validationResult)) {
|
333
|
+
return {
|
334
|
+
failure: validationResult.failure
|
335
|
+
};
|
336
|
+
}
|
337
|
+
return { success: validationResult.success };
|
338
|
+
} else if (schema.type === "nullable") {
|
339
|
+
if (value === null || value === undefined) {
|
340
|
+
return { success: null };
|
341
|
+
}
|
342
|
+
const result = parse(schema.item, value);
|
343
|
+
if (isFailure(result)) {
|
344
|
+
return result;
|
345
|
+
}
|
346
|
+
return { success: result.success };
|
347
|
+
} else if (schema.type === "transform") {
|
348
|
+
const result = parse(schema.from, value);
|
349
|
+
if (isFailure(result)) {
|
350
|
+
return result;
|
351
|
+
}
|
352
|
+
const transformedResult = schema.transformer(result.success);
|
353
|
+
if (isFailure(transformedResult)) {
|
354
|
+
return {
|
355
|
+
failure: transformedResult.failure
|
356
|
+
};
|
357
|
+
}
|
358
|
+
return { success: transformedResult.success };
|
359
|
+
}
|
360
|
+
throw new Error(`Unsupported scheme type: ${schema.type}`);
|
361
|
+
}
|
362
|
+
export {
|
363
|
+
exports_validators as validate,
|
364
|
+
exports_types as type,
|
365
|
+
exports_transformers as transform,
|
366
|
+
parse
|
367
|
+
};
|
package/dist/result.d.ts
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
export type Success<Value extends unknown> = {
|
2
|
+
success: Value;
|
3
|
+
};
|
4
|
+
export type Failure<Error extends unknown> = {
|
5
|
+
failure: Error;
|
6
|
+
};
|
7
|
+
export type Result<Value extends unknown, Error extends unknown> = Success<Value> | Failure<Error>;
|
8
|
+
export declare function isSuccess<Value extends unknown, Error extends unknown>(result: Result<Value, Error>): result is Success<Value>;
|
9
|
+
export declare function isFailure<Value extends unknown, Error extends unknown>(result: Result<Value, Error>): result is Failure<Error>;
|
10
|
+
export declare function expectSuccess<Value extends unknown, Error extends unknown>(result: Result<Value, Error>, message?: string): Value;
|
11
|
+
export declare function expectFailure<Value extends unknown, Error extends unknown>(result: Result<Value, Error>, message?: string): Error;
|
12
|
+
export declare function successOr<Value extends unknown, Error extends unknown>(result: Result<Value, Error>, defaultValue: Value): Value;
|
13
|
+
export declare function failureOr<Value extends unknown, Error extends unknown>(result: Result<Value, Error>, defaultError: Error): Error;
|
package/dist/schema.d.ts
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
import type { Result } from "./result";
|
2
|
+
export type Validator<T extends unknown> = (value: T) => Result<T, string[]>;
|
3
|
+
export type Transformer<T extends unknown, U extends unknown> = (value: T) => Result<U, string[]>;
|
4
|
+
export type Fold<T extends unknown> = {} & {
|
5
|
+
[P in keyof T]: T[P];
|
6
|
+
};
|
7
|
+
export type LiteralSchema<Literal extends unknown> = {
|
8
|
+
readonly type: "literal";
|
9
|
+
readonly literal: Literal;
|
10
|
+
readonly infer: Literal;
|
11
|
+
readonly message?: string;
|
12
|
+
};
|
13
|
+
export type NoneSchema = {
|
14
|
+
readonly type: "none";
|
15
|
+
readonly infer: null | undefined;
|
16
|
+
readonly message?: string;
|
17
|
+
};
|
18
|
+
export type IntSchema = {
|
19
|
+
readonly type: "int";
|
20
|
+
readonly infer: number;
|
21
|
+
readonly message?: string;
|
22
|
+
};
|
23
|
+
export type FloatSchema = {
|
24
|
+
readonly type: "float";
|
25
|
+
readonly infer: number;
|
26
|
+
readonly message?: string;
|
27
|
+
};
|
28
|
+
export type StringSchema = {
|
29
|
+
readonly type: "string";
|
30
|
+
readonly infer: string;
|
31
|
+
readonly message?: string;
|
32
|
+
};
|
33
|
+
export type BooleanSchema = {
|
34
|
+
readonly type: "boolean";
|
35
|
+
readonly infer: boolean;
|
36
|
+
readonly message?: string;
|
37
|
+
};
|
38
|
+
export type ArraySchema<Item extends Schema> = {
|
39
|
+
readonly type: "array";
|
40
|
+
readonly item: Item;
|
41
|
+
readonly infer: Item["infer"][];
|
42
|
+
readonly message?: string;
|
43
|
+
};
|
44
|
+
export type UnionSchema<Items extends ReadonlyArray<Schema>> = {
|
45
|
+
readonly type: "union";
|
46
|
+
readonly items: Items;
|
47
|
+
readonly infer: Items[number]["infer"];
|
48
|
+
readonly message?: string;
|
49
|
+
};
|
50
|
+
export type TupleSchema<Items extends ReadonlyArray<Schema>> = {
|
51
|
+
readonly type: "tuple";
|
52
|
+
readonly items: Items;
|
53
|
+
readonly infer: {
|
54
|
+
[Index in keyof Items]: Items[Index]["infer"];
|
55
|
+
};
|
56
|
+
readonly message?: string;
|
57
|
+
};
|
58
|
+
export type ObjectSchema<Props extends Record<string, Schema>> = {
|
59
|
+
readonly type: "object";
|
60
|
+
readonly props: Props;
|
61
|
+
readonly infer: Fold<{
|
62
|
+
-readonly [Key in keyof Props as Props[Key] extends NullableSchema<any> ? never : Key]: Props[Key]["infer"];
|
63
|
+
} & {
|
64
|
+
-readonly [Key in keyof Props as Props[Key] extends NullableSchema<any> ? Key : never]?: Props[Key]["infer"];
|
65
|
+
}>;
|
66
|
+
readonly message?: string;
|
67
|
+
};
|
68
|
+
export type NullableSchema<Item extends Schema> = {
|
69
|
+
readonly type: "nullable";
|
70
|
+
readonly item: Item;
|
71
|
+
readonly infer: Item["infer"] | null | undefined;
|
72
|
+
readonly message?: string;
|
73
|
+
};
|
74
|
+
export type ValidationSchema<Item extends Schema> = {
|
75
|
+
readonly type: "validation";
|
76
|
+
readonly item: Item;
|
77
|
+
readonly validator: Validator<Item>;
|
78
|
+
readonly infer: Item["infer"];
|
79
|
+
};
|
80
|
+
export type TransformSchema<From extends Schema, To extends Schema> = {
|
81
|
+
readonly type: "transform";
|
82
|
+
readonly from: From;
|
83
|
+
readonly to: To;
|
84
|
+
readonly transformer: Transformer<From["infer"], To["infer"]>;
|
85
|
+
readonly infer: To["infer"];
|
86
|
+
};
|
87
|
+
export type Schema = LiteralSchema<any> | NoneSchema | IntSchema | FloatSchema | StringSchema | BooleanSchema | ArraySchema<any> | UnionSchema<any[]> | TupleSchema<any[]> | ObjectSchema<any> | NullableSchema<any> | ValidationSchema<any> | TransformSchema<any, any>;
|
@@ -0,0 +1,4 @@
|
|
1
|
+
import type { Schema, Transformer, TransformSchema } from "./schema";
|
2
|
+
export declare function Transformer<const From extends Schema, const To extends Schema>(from: From, to: To, transformer: Transformer<From["infer"], To["infer"]>): TransformSchema<From, To>;
|
3
|
+
export declare function ToString<const From extends Schema>(from: From, message?: string): TransformSchema<From, import("./schema").StringSchema>;
|
4
|
+
export declare function ToInt<const From extends Schema>(from: From, message?: string): TransformSchema<From, import("./schema").IntSchema>;
|
package/dist/types.d.ts
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
import type { Schema, ArraySchema, BooleanSchema, FloatSchema, IntSchema, NullableSchema, ObjectSchema, StringSchema, TupleSchema, UnionSchema, LiteralSchema, NoneSchema } from "./schema";
|
2
|
+
export declare function Literal<T extends string | number | boolean>(literal: T, message?: string): LiteralSchema<T>;
|
3
|
+
export declare function None(): NoneSchema;
|
4
|
+
export declare function Int(message?: string): IntSchema;
|
5
|
+
export declare function Float(message?: string): FloatSchema;
|
6
|
+
export declare function String(message?: string): StringSchema;
|
7
|
+
export declare function Boolean(message?: string): BooleanSchema;
|
8
|
+
export declare function Array<const Item extends Schema>(item: Item, message?: string): ArraySchema<Item>;
|
9
|
+
export declare function Union<const Items extends ReadonlyArray<Schema>>(items: Items, message?: string): UnionSchema<Items>;
|
10
|
+
export declare function Tuple<const Items extends ReadonlyArray<Schema>>(items: Items, message?: string): TupleSchema<Items>;
|
11
|
+
export declare function Object<Props extends Record<string, Schema>>(props: Props, message?: string): ObjectSchema<Props>;
|
12
|
+
export declare function Nullable<S extends Schema>(item: S, message?: string): NullableSchema<S>;
|
package/dist/utils.d.ts
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
import { type Result } from "./result";
|
2
|
+
import type { Schema } from "./schema";
|
3
|
+
type ParseError<Value extends unknown = unknown> = Value extends Record<string, unknown> ? {
|
4
|
+
[K in keyof Value]: ParseError<Value[K]>;
|
5
|
+
} : string[];
|
6
|
+
export declare function parse<const S extends Schema, Infer extends unknown = S["infer"]>(schema: S, value: unknown): Result<Infer, ParseError<Infer>>;
|
7
|
+
export {};
|
@@ -0,0 +1,4 @@
|
|
1
|
+
import type { Schema, ValidationSchema, Validator } from "./schema";
|
2
|
+
export declare function Validator<const Item extends Schema>(item: Item, validator: Validator<Item["infer"]>): ValidationSchema<Item>;
|
3
|
+
export declare function Min<const Item extends Schema>(item: Item, min: number, message?: string): ValidationSchema<Item>;
|
4
|
+
export declare function Max<const Item extends Schema>(item: Item, max: number, message?: string): ValidationSchema<Item>;
|
package/package.json
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"name": "lightv-schema",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"description": "A lightweight schema validation library for TypeScript.",
|
5
|
+
"module": "src/index.ts",
|
6
|
+
"type": "module",
|
7
|
+
"main": "dist/index.js",
|
8
|
+
"types": "dist/index.d.ts",
|
9
|
+
"files": [
|
10
|
+
"dist/*.js",
|
11
|
+
"dist/*.d.ts"
|
12
|
+
],
|
13
|
+
"scripts": {
|
14
|
+
"build": "bun build --target=node ./src/index.ts --outfile=dist/index.js && bun run build:declaration",
|
15
|
+
"build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json",
|
16
|
+
"postbuild": "rimraf tsconfig.types.tsbuildinfo"
|
17
|
+
},
|
18
|
+
"license": "MIT",
|
19
|
+
"exports": {
|
20
|
+
".": {
|
21
|
+
"import": "./dist/index.js",
|
22
|
+
"types": "./dist/index.d.ts"
|
23
|
+
},
|
24
|
+
"./scheme": {
|
25
|
+
"types": "./dist/scheme.d.ts"
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"devDependencies": {
|
29
|
+
"@types/bun": "latest"
|
30
|
+
},
|
31
|
+
"peerDependencies": {
|
32
|
+
"typescript": "^5.0.0"
|
33
|
+
}
|
34
|
+
}
|