@esmj/schema 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/{array.d.cts → array.d.mts} +1 -1
- package/dist/array.mjs +1 -0
- package/dist/chunk-BV6SWQSH.mjs +1 -0
- package/dist/chunk-PHNKAD7Q.mjs +1 -0
- package/dist/chunk-SHVCROKM.mjs +1 -0
- package/dist/{full.d.cts → full.d.mts} +4 -4
- package/dist/full.mjs +1 -0
- package/dist/index.mjs +1 -0
- package/dist/{number.d.cts → number.d.mts} +1 -1
- package/dist/number.mjs +1 -0
- package/dist/{string.d.cts → string.d.mts} +1 -1
- package/dist/string.mjs +1 -0
- package/package.json +8 -9
- package/dist/array.js +0 -1
- package/dist/chunk-6ABUMTDR.js +0 -1
- package/dist/chunk-JFGD5PND.js +0 -1
- package/dist/chunk-QEBUM44M.js +0 -1
- package/dist/full.js +0 -1
- package/dist/index.js +0 -1
- package/dist/number.js +0 -1
- package/dist/string.js +0 -1
- package/examples/advanced-forms.ts +0 -138
- package/examples/basic-usage.ts +0 -41
- package/examples/custom-extensions.ts +0 -120
- package/examples/custom-validation.ts +0 -110
- package/tsconfig.json +0 -12
- /package/dist/{chunk-5ARMWSHU.js → chunk-NCHMO7B3.mjs} +0 -0
- /package/dist/{index.d.cts → index.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -117,15 +117,15 @@ When choosing a schema validation library, bundle size can be an important facto
|
|
|
117
117
|
|
|
118
118
|
| Library | Bundle Size (minified + gzipped) |
|
|
119
119
|
|-------------------|---------------------------------|
|
|
120
|
-
| `@esmj/schema` | `~1
|
|
120
|
+
| `@esmj/schema` | `~1.5 KB` |
|
|
121
121
|
| Superstruct | ~3.2 KB |
|
|
122
122
|
| @sinclair/typebox | ~11.7 KB |
|
|
123
123
|
| Yup | ~12.2 KB |
|
|
124
124
|
| Zod@3 | ~13 KB |
|
|
125
|
-
| @zod/mini | ~20
|
|
126
|
-
| Joi | ~40
|
|
127
|
-
| Zod@4 | ~40
|
|
128
|
-
| ArkType | ~41
|
|
125
|
+
| @zod/mini | ~20.5 KB |
|
|
126
|
+
| Joi | ~40.4 KB |
|
|
127
|
+
| Zod@4 | ~40.8 KB |
|
|
128
|
+
| ArkType | ~41.8 KB |
|
|
129
129
|
| Effect/Schema | ~115.5 KB |
|
|
130
130
|
|
|
131
131
|
### Performance Comparison
|
|
@@ -229,7 +229,7 @@ console.log(result);
|
|
|
229
229
|
### Import Options
|
|
230
230
|
|
|
231
231
|
```typescript
|
|
232
|
-
// Minimal version (core only, ~1.
|
|
232
|
+
// Minimal version (core only, ~1.5 KB)
|
|
233
233
|
import { s } from '@esmj/schema';
|
|
234
234
|
|
|
235
235
|
// Full version (all extensions included, ~4 KB)
|
|
@@ -252,7 +252,7 @@ import { s } from '@esmj/schema';
|
|
|
252
252
|
|
|
253
253
|
### Bundle Size Impact
|
|
254
254
|
|
|
255
|
-
- **Core only** (`@esmj/schema`): ~1.
|
|
255
|
+
- **Core only** (`@esmj/schema`): ~1.5 KB gzipped
|
|
256
256
|
- **String extensions** (`@esmj/schema/string`): +~0.8 KB
|
|
257
257
|
- **Number extensions** (`@esmj/schema/number`): +~0.6 KB
|
|
258
258
|
- **Array extensions** (`@esmj/schema/array`): +~0.5 KB
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.
|
|
1
|
+
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.mjs';
|
|
2
2
|
|
|
3
3
|
declare module './index.ts' {
|
|
4
4
|
interface ArraySchemaInterface<T extends SchemaType> {
|
package/dist/array.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import'./chunk-PHNKAD7Q.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-NCHMO7B3.mjs';c((i,s,c)=>{if(c?.type==="string"){let r=i;r.min=function(t,{message:n}={}){return this.refine(e=>e.length>=t,{message:n||(e=>`String must be at least ${t} characters long (received ${e.length} characters: "${e}")`)})},r.max=function(t,{message:n}={}){return this.refine(e=>e.length<=t,{message:n||(e=>`String must be at most ${t} characters long (received ${e.length} characters: "${e}")`)})},r.length=function(t,{message:n}={}){return this.refine(e=>e.length===t,{message:n||(e=>`String must be exactly ${t} characters long (received ${e.length} characters: "${e}")`)})},r.nonEmpty=function({message:t}={}){return this.refine(n=>n.length>0,{message:t||"String must not be empty (received empty string)"})},r.startsWith=function(t,{message:n}={}){return this.refine(e=>e.startsWith(t),{message:n||(e=>`String must start with "${t}" (received: "${e}")`)})},r.endsWith=function(t,{message:n}={}){return this.refine(e=>e.endsWith(t),{message:n||(e=>`String must end with "${t}" (received: "${e}")`)})},r.includes=function(t,{message:n}={}){return this.refine(e=>e.includes(t),{message:n||(e=>`String must include "${t}" (received: "${e}")`)})},r.toLowerCase=function(){return this.transform(t=>t.toLowerCase())},r.toUpperCase=function(){return this.transform(t=>t.toUpperCase())},r.trim=function(){return this.transform(t=>t.trim())},r.padStart=function(t,n=" "){return this.transform(e=>e.padStart(t,n))},r.padEnd=function(t,n=" "){return this.transform(e=>e.padEnd(t,n))},r.replace=function(t,n){return this.transform(e=>e.replace(t,n))};}return i});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-NCHMO7B3.mjs';c((a,o,m)=>{if(m?.type==="array"){let r=a;r.min=function(e,{message:t}={}){return this.refine(n=>n.length>=e,{message:t||`Array must contain at least ${e} items.`})},r.max=function(e,{message:t}={}){return this.refine(n=>n.length<=e,{message:t||`Array must contain at most ${e} items.`})},r.length=function(e,{message:t}={}){return this.refine(n=>n.length===e,{message:t||`Array must contain exactly ${e} items.`})},r.nonEmpty=function({message:e}={}){return this.refine(t=>t.length>0,{message:e||"Array must not be empty."})},r.unique=function({message:e}={}){return this.refine(t=>{let n=new Set;try{return t.every(c=>{let s=JSON.stringify(c);return n.has(s)?!1:(n.add(s),!0)})}catch{return new Set(t).size===t.length}},{message:e||"Array items must be unique."})},r.sort=function(){return this.transform(e=>[...e].sort())},r.reverse=function(){return this.transform(e=>[...e].reverse())};}return a});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-NCHMO7B3.mjs';c((i,c,m)=>{if(m?.type==="number"){let n=i;n.min=function(e,{message:t}={}){return this.refine(r=>r>=e,{message:t||`Number must be greater than or equal to ${e}.`})},n.max=function(e,{message:t}={}){return this.refine(r=>r<=e,{message:t||`Number must be less than or equal to ${e}.`})},n.positive=function({message:e}={}){return this.refine(t=>t>0,{message:e||"Number must be positive."})},n.negative=function({message:e}={}){return this.refine(t=>t<0,{message:e||"Number must be negative."})},n.int=function({message:e}={}){return this.refine(t=>Number.isInteger(t),{message:e||"Number must be an integer."})},n.float=function({message:e}={}){return this.refine(t=>Number.isFinite(t)&&!Number.isInteger(t),{message:e||"Number must be a floating point (non-integer)."})},n.multipleOf=function(e,{message:t}={}){return this.refine(r=>r%e===0,{message:t||`Number must be a multiple of ${e}.`})},n.finite=function({message:e}={}){return this.refine(t=>Number.isFinite(t),{message:e||"Number must be finite."})};}return i});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import './string.
|
|
2
|
-
import './number.
|
|
3
|
-
import './array.
|
|
4
|
-
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.
|
|
1
|
+
import './string.mjs';
|
|
2
|
+
import './number.mjs';
|
|
3
|
+
import './array.mjs';
|
|
4
|
+
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.mjs';
|
package/dist/full.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import'./chunk-PHNKAD7Q.mjs';import'./chunk-SHVCROKM.mjs';import'./chunk-BV6SWQSH.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.
|
|
1
|
+
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.mjs';
|
|
2
2
|
|
|
3
3
|
declare module './index.ts' {
|
|
4
4
|
interface NumberSchemaInterface {
|
package/dist/number.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import'./chunk-SHVCROKM.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.
|
|
1
|
+
export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.mjs';
|
|
2
2
|
|
|
3
3
|
declare module './index.ts' {
|
|
4
4
|
interface StringSchemaInterface {
|
package/dist/string.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import'./chunk-BV6SWQSH.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmj/schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Tiny extendable package for schema validation.",
|
|
5
|
-
"type": "module",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"schema",
|
|
8
7
|
"validation",
|
|
@@ -20,33 +19,33 @@
|
|
|
20
19
|
"joi",
|
|
21
20
|
"arktype"
|
|
22
21
|
],
|
|
23
|
-
"main": "dist/index",
|
|
24
|
-
"module": "dist/index",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"module": "./dist/index.mjs",
|
|
25
24
|
"exports": {
|
|
26
25
|
".": {
|
|
27
26
|
"types": "./dist/index.d.ts",
|
|
28
27
|
"import": "./dist/index.mjs",
|
|
29
|
-
"require": "./dist/index.
|
|
28
|
+
"require": "./dist/index.cjs"
|
|
30
29
|
},
|
|
31
30
|
"./full": {
|
|
32
31
|
"types": "./dist/full.d.ts",
|
|
33
32
|
"import": "./dist/full.mjs",
|
|
34
|
-
"require": "./dist/full.
|
|
33
|
+
"require": "./dist/full.cjs"
|
|
35
34
|
},
|
|
36
35
|
"./string": {
|
|
37
36
|
"types": "./dist/string.d.ts",
|
|
38
37
|
"import": "./dist/string.mjs",
|
|
39
|
-
"require": "./dist/string.
|
|
38
|
+
"require": "./dist/string.cjs"
|
|
40
39
|
},
|
|
41
40
|
"./number": {
|
|
42
41
|
"types": "./dist/number.d.ts",
|
|
43
42
|
"import": "./dist/number.mjs",
|
|
44
|
-
"require": "./dist/number.
|
|
43
|
+
"require": "./dist/number.cjs"
|
|
45
44
|
},
|
|
46
45
|
"./array": {
|
|
47
46
|
"types": "./dist/array.d.ts",
|
|
48
47
|
"import": "./dist/array.mjs",
|
|
49
|
-
"require": "./dist/array.
|
|
48
|
+
"require": "./dist/array.cjs"
|
|
50
49
|
}
|
|
51
50
|
},
|
|
52
51
|
"sideEffects": [
|
package/dist/array.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import'./chunk-JFGD5PND.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
|
package/dist/chunk-6ABUMTDR.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import {c}from'./chunk-5ARMWSHU.js';c((i,s,c)=>{if(c?.type==="string"){let r=i;r.min=function(t,{message:n}={}){return this.refine(e=>e.length>=t,{message:n||(e=>`String must be at least ${t} characters long (received ${e.length} characters: "${e}")`)})},r.max=function(t,{message:n}={}){return this.refine(e=>e.length<=t,{message:n||(e=>`String must be at most ${t} characters long (received ${e.length} characters: "${e}")`)})},r.length=function(t,{message:n}={}){return this.refine(e=>e.length===t,{message:n||(e=>`String must be exactly ${t} characters long (received ${e.length} characters: "${e}")`)})},r.nonEmpty=function({message:t}={}){return this.refine(n=>n.length>0,{message:t||"String must not be empty (received empty string)"})},r.startsWith=function(t,{message:n}={}){return this.refine(e=>e.startsWith(t),{message:n||(e=>`String must start with "${t}" (received: "${e}")`)})},r.endsWith=function(t,{message:n}={}){return this.refine(e=>e.endsWith(t),{message:n||(e=>`String must end with "${t}" (received: "${e}")`)})},r.includes=function(t,{message:n}={}){return this.refine(e=>e.includes(t),{message:n||(e=>`String must include "${t}" (received: "${e}")`)})},r.toLowerCase=function(){return this.transform(t=>t.toLowerCase())},r.toUpperCase=function(){return this.transform(t=>t.toUpperCase())},r.trim=function(){return this.transform(t=>t.trim())},r.padStart=function(t,n=" "){return this.transform(e=>e.padStart(t,n))},r.padEnd=function(t,n=" "){return this.transform(e=>e.padEnd(t,n))},r.replace=function(t,n){return this.transform(e=>e.replace(t,n))};}return i});
|
package/dist/chunk-JFGD5PND.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import {c}from'./chunk-5ARMWSHU.js';c((a,o,m)=>{if(m?.type==="array"){let r=a;r.min=function(e,{message:t}={}){return this.refine(n=>n.length>=e,{message:t||`Array must contain at least ${e} items.`})},r.max=function(e,{message:t}={}){return this.refine(n=>n.length<=e,{message:t||`Array must contain at most ${e} items.`})},r.length=function(e,{message:t}={}){return this.refine(n=>n.length===e,{message:t||`Array must contain exactly ${e} items.`})},r.nonEmpty=function({message:e}={}){return this.refine(t=>t.length>0,{message:e||"Array must not be empty."})},r.unique=function({message:e}={}){return this.refine(t=>{let n=new Set;try{return t.every(c=>{let s=JSON.stringify(c);return n.has(s)?!1:(n.add(s),!0)})}catch{return new Set(t).size===t.length}},{message:e||"Array items must be unique."})},r.sort=function(){return this.transform(e=>[...e].sort())},r.reverse=function(){return this.transform(e=>[...e].reverse())};}return a});
|
package/dist/chunk-QEBUM44M.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import {c}from'./chunk-5ARMWSHU.js';c((i,c,m)=>{if(m?.type==="number"){let n=i;n.min=function(e,{message:t}={}){return this.refine(r=>r>=e,{message:t||`Number must be greater than or equal to ${e}.`})},n.max=function(e,{message:t}={}){return this.refine(r=>r<=e,{message:t||`Number must be less than or equal to ${e}.`})},n.positive=function({message:e}={}){return this.refine(t=>t>0,{message:e||"Number must be positive."})},n.negative=function({message:e}={}){return this.refine(t=>t<0,{message:e||"Number must be negative."})},n.int=function({message:e}={}){return this.refine(t=>Number.isInteger(t),{message:e||"Number must be an integer."})},n.float=function({message:e}={}){return this.refine(t=>Number.isFinite(t)&&!Number.isInteger(t),{message:e||"Number must be a floating point (non-integer)."})},n.multipleOf=function(e,{message:t}={}){return this.refine(r=>r%e===0,{message:t||`Number must be a multiple of ${e}.`})},n.finite=function({message:e}={}){return this.refine(t=>Number.isFinite(t),{message:e||"Number must be finite."})};}return i});
|
package/dist/full.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import'./chunk-JFGD5PND.js';import'./chunk-QEBUM44M.js';import'./chunk-6ABUMTDR.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
|
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
|
package/dist/number.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import'./chunk-QEBUM44M.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
|
package/dist/string.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import'./chunk-6ABUMTDR.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { s } from '../src/full.ts';
|
|
2
|
-
|
|
3
|
-
// Advanced form validation example
|
|
4
|
-
const addressSchema = s.object({
|
|
5
|
-
street: s.string().min(3).max(100),
|
|
6
|
-
city: s.string().min(2).max(50),
|
|
7
|
-
zipCode: s.string().length(5).refine((val) => /^\d{5}$/.test(val), {
|
|
8
|
-
message: 'ZIP code must be 5 digits',
|
|
9
|
-
}),
|
|
10
|
-
country: s.enum(['US', 'CA', 'MX', 'UK']),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const userProfileSchema = s.object({
|
|
14
|
-
// Personal info
|
|
15
|
-
firstName: s.string().trim().min(2).max(50),
|
|
16
|
-
lastName: s.string().trim().min(2).max(50),
|
|
17
|
-
email: s
|
|
18
|
-
.string()
|
|
19
|
-
.trim()
|
|
20
|
-
.toLowerCase()
|
|
21
|
-
.refine((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), {
|
|
22
|
-
message: 'Invalid email address',
|
|
23
|
-
}),
|
|
24
|
-
|
|
25
|
-
// Contact
|
|
26
|
-
phone: s
|
|
27
|
-
.string()
|
|
28
|
-
.optional()
|
|
29
|
-
.transform((val) => val?.replace(/\D/g, ''))
|
|
30
|
-
.refine((val) => !val || val.length === 10, {
|
|
31
|
-
message: 'Phone number must be 10 digits',
|
|
32
|
-
}),
|
|
33
|
-
|
|
34
|
-
// Address
|
|
35
|
-
address: addressSchema.optional(),
|
|
36
|
-
|
|
37
|
-
// Preferences
|
|
38
|
-
role: s.enum(['admin', 'editor', 'viewer']).default('viewer'),
|
|
39
|
-
tags: s.array(s.string()).min(1).max(5).unique(),
|
|
40
|
-
isActive: s.boolean().default(true),
|
|
41
|
-
|
|
42
|
-
// Metadata
|
|
43
|
-
createdAt: s.date(),
|
|
44
|
-
updatedAt: s.date().optional(),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
console.log('=== Valid User Profile ===');
|
|
48
|
-
const validProfile = {
|
|
49
|
-
firstName: ' John ',
|
|
50
|
-
lastName: 'Doe',
|
|
51
|
-
email: ' JOHN.DOE@EXAMPLE.COM ',
|
|
52
|
-
phone: '(555) 123-4567',
|
|
53
|
-
address: {
|
|
54
|
-
street: '123 Main St',
|
|
55
|
-
city: 'New York',
|
|
56
|
-
zipCode: '10001',
|
|
57
|
-
country: 'US' as const,
|
|
58
|
-
},
|
|
59
|
-
role: 'admin' as const,
|
|
60
|
-
tags: ['developer', 'typescript', 'node'],
|
|
61
|
-
isActive: true,
|
|
62
|
-
createdAt: new Date(),
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
console.log('Input:', validProfile);
|
|
66
|
-
console.log('Parsed:', userProfileSchema.parse(validProfile));
|
|
67
|
-
|
|
68
|
-
console.log('\n=== Invalid User Profile (missing required fields) ===');
|
|
69
|
-
const invalidProfile = {
|
|
70
|
-
firstName: 'John',
|
|
71
|
-
// lastName missing
|
|
72
|
-
email: 'invalid-email',
|
|
73
|
-
tags: [],
|
|
74
|
-
createdAt: new Date(),
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
console.log('Result:', userProfileSchema.safeParse(invalidProfile));
|
|
78
|
-
|
|
79
|
-
console.log('\n=== Invalid ZIP Code ===');
|
|
80
|
-
const invalidZipProfile = {
|
|
81
|
-
...validProfile,
|
|
82
|
-
address: {
|
|
83
|
-
street: '123 Main St',
|
|
84
|
-
city: 'New York',
|
|
85
|
-
zipCode: 'ABC12', // Invalid: not digits
|
|
86
|
-
country: 'US' as const,
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
console.log('Result:', userProfileSchema.safeParse(invalidZipProfile));
|
|
91
|
-
|
|
92
|
-
// API response validation
|
|
93
|
-
const apiResponseSchema = s.object({
|
|
94
|
-
status: s.enum(['success', 'error']),
|
|
95
|
-
data: s
|
|
96
|
-
.object({
|
|
97
|
-
users: s.array(
|
|
98
|
-
s.object({
|
|
99
|
-
id: s.number().positive().int(),
|
|
100
|
-
name: s.string(),
|
|
101
|
-
email: s.string(),
|
|
102
|
-
}),
|
|
103
|
-
),
|
|
104
|
-
total: s.number().positive().int(),
|
|
105
|
-
})
|
|
106
|
-
.optional(),
|
|
107
|
-
error: s
|
|
108
|
-
.object({
|
|
109
|
-
code: s.string(),
|
|
110
|
-
message: s.string(),
|
|
111
|
-
})
|
|
112
|
-
.optional(),
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
console.log('\n=== API Response Validation (Success) ===');
|
|
116
|
-
const successResponse = {
|
|
117
|
-
status: 'success' as const,
|
|
118
|
-
data: {
|
|
119
|
-
users: [
|
|
120
|
-
{ id: 1, name: 'John', email: 'john@example.com' },
|
|
121
|
-
{ id: 2, name: 'Jane', email: 'jane@example.com' },
|
|
122
|
-
],
|
|
123
|
-
total: 2,
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
console.log('Result:', apiResponseSchema.parse(successResponse));
|
|
128
|
-
|
|
129
|
-
console.log('\n=== API Response Validation (Error) ===');
|
|
130
|
-
const errorResponse = {
|
|
131
|
-
status: 'error' as const,
|
|
132
|
-
error: {
|
|
133
|
-
code: 'NOT_FOUND',
|
|
134
|
-
message: 'User not found',
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
console.log('Result:', apiResponseSchema.parse(errorResponse));
|
package/examples/basic-usage.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { s } from '../src/full.ts';
|
|
2
|
-
|
|
3
|
-
// String validations with transformations
|
|
4
|
-
console.log('=== String Validations ===');
|
|
5
|
-
console.log(
|
|
6
|
-
'trim + startsWith + endsWith:',
|
|
7
|
-
s
|
|
8
|
-
.string()
|
|
9
|
-
.trim()
|
|
10
|
-
.startsWith('Hello')
|
|
11
|
-
.endsWith('World')
|
|
12
|
-
.safeParse(' Hello, World '),
|
|
13
|
-
);
|
|
14
|
-
console.log(
|
|
15
|
-
'startsWith + endsWith (without trim):',
|
|
16
|
-
s.string().startsWith('Hello').endsWith('World').safeParse(' Hello, World '),
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
// Array validations
|
|
20
|
-
console.log('\n=== Array Validations ===');
|
|
21
|
-
console.log(
|
|
22
|
-
'Array with min/max:',
|
|
23
|
-
s.array(s.string()).min(2).max(5).safeParse(['Hello', 'World']),
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
// Number validations
|
|
27
|
-
console.log('\n=== Number Validations ===');
|
|
28
|
-
console.log('Integer + positive:', s.number().int().positive().safeParse(42));
|
|
29
|
-
console.log('Float validation:', s.number().float().safeParse(3.14));
|
|
30
|
-
|
|
31
|
-
// Union with extended methods
|
|
32
|
-
console.log('\n=== Union Validations ===');
|
|
33
|
-
console.log(
|
|
34
|
-
'Union with string validation:',
|
|
35
|
-
s
|
|
36
|
-
.union([
|
|
37
|
-
s.string({ message: 'stringSchema' }).startsWith('Hello'),
|
|
38
|
-
s.number(),
|
|
39
|
-
])
|
|
40
|
-
.safeParse('World'),
|
|
41
|
-
);
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { s, extend, type StringSchemaInterface } from '../src/index.ts';
|
|
2
|
-
|
|
3
|
-
// Extend StringSchemaInterface to add custom methods
|
|
4
|
-
declare module '../src/index.ts' {
|
|
5
|
-
interface StringSchemaInterface {
|
|
6
|
-
email(options?: { message?: string }): StringSchemaInterface;
|
|
7
|
-
url(options?: { message?: string }): StringSchemaInterface;
|
|
8
|
-
uuid(options?: { message?: string }): StringSchemaInterface;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Implement the extensions
|
|
13
|
-
extend((schema, _, options) => {
|
|
14
|
-
if (options?.type === 'string') {
|
|
15
|
-
const stringSchema = schema as StringSchemaInterface;
|
|
16
|
-
|
|
17
|
-
// Email validation
|
|
18
|
-
stringSchema.email = function ({ message } = {}) {
|
|
19
|
-
return this.refine(
|
|
20
|
-
(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
|
|
21
|
-
{
|
|
22
|
-
message: message || ((value: string) => `"${value}" is not a valid email address`),
|
|
23
|
-
},
|
|
24
|
-
);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// URL validation
|
|
28
|
-
stringSchema.url = function ({ message } = {}) {
|
|
29
|
-
return this.refine(
|
|
30
|
-
(value) => {
|
|
31
|
-
try {
|
|
32
|
-
new URL(value);
|
|
33
|
-
return true;
|
|
34
|
-
} catch {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
message: message || ((value: string) => `"${value}" is not a valid URL`),
|
|
40
|
-
},
|
|
41
|
-
);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// UUID validation
|
|
45
|
-
stringSchema.uuid = function ({ message } = {}) {
|
|
46
|
-
return this.refine(
|
|
47
|
-
(value) =>
|
|
48
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
|
49
|
-
value,
|
|
50
|
-
),
|
|
51
|
-
{
|
|
52
|
-
message: message || ((value: string) => `"${value}" is not a valid UUID`),
|
|
53
|
-
},
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return schema;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Now use the extended schema
|
|
62
|
-
console.log('=== Email Validation ===');
|
|
63
|
-
const emailSchema = s.string().email();
|
|
64
|
-
console.log('Valid email:', emailSchema.safeParse('user@example.com'));
|
|
65
|
-
console.log('Invalid email:', emailSchema.safeParse('not-an-email'));
|
|
66
|
-
console.log('Empty string:', emailSchema.safeParse(''));
|
|
67
|
-
|
|
68
|
-
console.log('\n=== URL Validation ===');
|
|
69
|
-
const urlSchema = s.string().url();
|
|
70
|
-
console.log('Valid URL:', urlSchema.safeParse('https://example.com'));
|
|
71
|
-
console.log('Valid URL with path:', urlSchema.safeParse('https://example.com/path'));
|
|
72
|
-
console.log('Invalid URL:', urlSchema.safeParse('not a url'));
|
|
73
|
-
|
|
74
|
-
console.log('\n=== UUID Validation ===');
|
|
75
|
-
const uuidSchema = s.string().uuid();
|
|
76
|
-
console.log(
|
|
77
|
-
'Valid UUID:',
|
|
78
|
-
uuidSchema.safeParse('550e8400-e29b-41d4-a716-446655440000'),
|
|
79
|
-
);
|
|
80
|
-
console.log('Invalid UUID:', uuidSchema.safeParse('not-a-uuid'));
|
|
81
|
-
console.log(
|
|
82
|
-
'Invalid UUID format:',
|
|
83
|
-
uuidSchema.safeParse('550e8400-e29b-41d4-a716'),
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// Combine extensions in a schema
|
|
87
|
-
console.log('\n=== Combined Schema ===');
|
|
88
|
-
const userSchema = s.object({
|
|
89
|
-
id: s.string().uuid(),
|
|
90
|
-
email: s.string().trim().toLowerCase().email(),
|
|
91
|
-
website: s.string().url().optional(),
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
console.log(
|
|
95
|
-
'Valid user:',
|
|
96
|
-
userSchema.parse({
|
|
97
|
-
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
98
|
-
email: ' USER@EXAMPLE.COM ',
|
|
99
|
-
website: 'https://example.com',
|
|
100
|
-
}),
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
console.log(
|
|
104
|
-
'\nInvalid user (bad email):',
|
|
105
|
-
userSchema.safeParse({
|
|
106
|
-
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
107
|
-
email: 'not-an-email',
|
|
108
|
-
}),
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Custom error messages
|
|
112
|
-
console.log('\n=== Custom Error Messages ===');
|
|
113
|
-
const customEmailSchema = s
|
|
114
|
-
.string()
|
|
115
|
-
.email({ message: 'Please enter a valid email address' });
|
|
116
|
-
|
|
117
|
-
console.log(
|
|
118
|
-
'Custom error:',
|
|
119
|
-
customEmailSchema.safeParse('invalid'),
|
|
120
|
-
);
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { s } from '../src/full.ts';
|
|
2
|
-
|
|
3
|
-
// Custom email validation using refine
|
|
4
|
-
const emailSchema = s
|
|
5
|
-
.string()
|
|
6
|
-
.trim()
|
|
7
|
-
.toLowerCase()
|
|
8
|
-
.refine((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), {
|
|
9
|
-
message: 'Invalid email address format',
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
console.log('=== Custom Email Validation ===');
|
|
13
|
-
console.log('Valid email:', emailSchema.safeParse('user@example.com'));
|
|
14
|
-
console.log('Invalid email:', emailSchema.safeParse('not-an-email'));
|
|
15
|
-
console.log(
|
|
16
|
-
'Email with whitespace:',
|
|
17
|
-
emailSchema.safeParse(' User@Example.COM '),
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
// Custom URL validation
|
|
21
|
-
const urlSchema = s.string().refine(
|
|
22
|
-
(value) => {
|
|
23
|
-
try {
|
|
24
|
-
new URL(value);
|
|
25
|
-
return true;
|
|
26
|
-
} catch {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
message: (value) => `"${value}" is not a valid URL`,
|
|
32
|
-
},
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
console.log('\n=== Custom URL Validation ===');
|
|
36
|
-
console.log('Valid URL:', urlSchema.safeParse('https://example.com'));
|
|
37
|
-
console.log('Invalid URL:', urlSchema.safeParse('not a url'));
|
|
38
|
-
|
|
39
|
-
// Custom age validation
|
|
40
|
-
const ageSchema = s
|
|
41
|
-
.number()
|
|
42
|
-
.int()
|
|
43
|
-
.positive()
|
|
44
|
-
.refine((value) => value >= 18, {
|
|
45
|
-
message: (value) =>
|
|
46
|
-
`Age must be at least 18 (received ${value} years old)`,
|
|
47
|
-
})
|
|
48
|
-
.refine((value) => value <= 120, {
|
|
49
|
-
message: (value) => `Age seems unrealistic (received ${value} years old)`,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
console.log('\n=== Custom Age Validation ===');
|
|
53
|
-
console.log('Valid age:', ageSchema.safeParse(25));
|
|
54
|
-
console.log('Too young:', ageSchema.safeParse(15));
|
|
55
|
-
console.log('Too old:', ageSchema.safeParse(150));
|
|
56
|
-
|
|
57
|
-
// Custom password validation
|
|
58
|
-
const passwordSchema = s
|
|
59
|
-
.string()
|
|
60
|
-
.min(8, { message: 'Password must be at least 8 characters' })
|
|
61
|
-
.refine((value) => /[A-Z]/.test(value), {
|
|
62
|
-
message: 'Password must contain at least one uppercase letter',
|
|
63
|
-
})
|
|
64
|
-
.refine((value) => /[a-z]/.test(value), {
|
|
65
|
-
message: 'Password must contain at least one lowercase letter',
|
|
66
|
-
})
|
|
67
|
-
.refine((value) => /[0-9]/.test(value), {
|
|
68
|
-
message: 'Password must contain at least one number',
|
|
69
|
-
})
|
|
70
|
-
.refine((value) => /[^A-Za-z0-9]/.test(value), {
|
|
71
|
-
message: 'Password must contain at least one special character',
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
console.log('\n=== Custom Password Validation ===');
|
|
75
|
-
console.log('Valid password:', passwordSchema.safeParse('MyP@ssw0rd'));
|
|
76
|
-
console.log('Too short:', passwordSchema.safeParse('Pass1!'));
|
|
77
|
-
console.log('No uppercase:', passwordSchema.safeParse('myp@ssw0rd'));
|
|
78
|
-
console.log('No special char:', passwordSchema.safeParse('MyPassw0rd'));
|
|
79
|
-
|
|
80
|
-
// Custom object validation with cross-field checks
|
|
81
|
-
const registrationSchema = s
|
|
82
|
-
.object({
|
|
83
|
-
password: s.string().min(8),
|
|
84
|
-
confirmPassword: s.string(),
|
|
85
|
-
email: emailSchema,
|
|
86
|
-
age: ageSchema,
|
|
87
|
-
})
|
|
88
|
-
.refine((data) => data.password === data.confirmPassword, {
|
|
89
|
-
message: 'Passwords do not match',
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
console.log('\n=== Cross-Field Validation ===');
|
|
93
|
-
console.log(
|
|
94
|
-
'Valid registration:',
|
|
95
|
-
registrationSchema.safeParse({
|
|
96
|
-
password: 'MyP@ssw0rd',
|
|
97
|
-
confirmPassword: 'MyP@ssw0rd',
|
|
98
|
-
email: 'user@example.com',
|
|
99
|
-
age: 25,
|
|
100
|
-
}),
|
|
101
|
-
);
|
|
102
|
-
console.log(
|
|
103
|
-
'Password mismatch:',
|
|
104
|
-
registrationSchema.safeParse({
|
|
105
|
-
password: 'MyP@ssw0rd',
|
|
106
|
-
confirmPassword: 'Different123!',
|
|
107
|
-
email: 'user@example.com',
|
|
108
|
-
age: 25,
|
|
109
|
-
}),
|
|
110
|
-
);
|
package/tsconfig.json
DELETED
|
File without changes
|
|
File without changes
|