@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 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,4 KB` |
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,5 KB |
126
- | Joi | ~40,4 KB |
127
- | Zod@4 | ~40,8 KB |
128
- | ArkType | ~41,8 KB |
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.4 KB)
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.4 KB gzipped
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.cjs';
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.cjs';
2
- import './number.cjs';
3
- import './array.cjs';
4
- export { ArraySchemaInterface, BooleanSchemaInterface, DateSchemaInterface, EnumSchemaInterface, ErrorStructure, ExtenderType, Infer, Invalid, NumberSchemaInterface, ObjectSchemaInterface, SchemaInterface, SchemaInterfaceOptions, SchemaType, StringSchemaInterface, UnionSchemaInterface, Valid, extend, hookOriginal, s } from './index.cjs';
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.cjs';
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 {
@@ -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.cjs';
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 {
@@ -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.5.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.js"
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.js"
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.js"
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.js"
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.js"
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';
@@ -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});
@@ -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});
@@ -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));
@@ -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
@@ -1,12 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2022",
4
- "module": "es2022",
5
- "moduleResolution": "node",
6
- "esModuleInterop": true,
7
- "allowImportingTsExtensions": true,
8
- "resolveJsonModule": true,
9
- "noEmit": true
10
- },
11
- "include": ["src/**/*"]
12
- }
File without changes
File without changes