Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@esmj/schema

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@esmj/schema - npm Package Compare versions

Comparing version
0.5.0
to
0.5.1
+1
dist/array.mjs
import'./chunk-PHNKAD7Q.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
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});
var P={abortEarly:true};function d(e,s){if(!s)return e;let o=e?.cause?.key?`${s}.${e.cause.key}`:`${s}`;return {message:`Error parsing key "${o}": ${e.message}`,cause:{key:o}}}function b(e,s,o){!e.errors||e.errors.length===0||e.errors.forEach(i=>{let f=d(i,o);s.push(f);});}function y(e){return {...P,...e}}var x=e=>typeof e=="string"||e instanceof String,k=e=>typeof e=="number"||e instanceof Number,w=e=>e===true||e===false,E=e=>e instanceof Date&&!Number.isNaN(e.getTime()),_=e=>Array.isArray(e),g=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),R={object(e,s){let o=l(g,{...s,type:"object"});return o._getDescription=()=>`object({ ${Object.entries(e).map(([f,c])=>`${f}: ${c._getDescription()}`).join(", ")} })`,h(o,"_parse",(i,f,c)=>{let t=i(f,c),{abortEarly:r}=y(c);if(t.success===false)return t;let a={},n=[];for(let u in e){let p=e[u]._parse(t.data[u],c);if(p.success)a[u]=p.data;else {if(p=p,r!==false){let m=d(p.error,u);return {success:false,error:m,errors:[m]}}b(p,n,u);}}return n.length>0?{success:false,error:n[0],errors:n}:{success:true,data:a}}),o},string(e){return l(x,{...e,type:"string"})},number(e){return l(k,{...e,type:"number"})},boolean(e){return l(w,{...e,type:"boolean"})},date(e){return l(E,{...e,type:"date"})},enum(e,s){let o=t=>e.includes(t),i=t=>`Invalid ${f} value. Expected ${e.map(r=>`"${r}"`).join(" | ")}, received "${t}".`,f="enum",c=l(o,{message:i,...s,type:f});return c._getDescription=()=>`enum(${e.map(t=>`"${t}"`).join(" | ")})`,c},array(e,s){let o=l(_,{...s,type:"array"});return o._getDescription=()=>`array(${e._getDescription()})`,h(o,"_parse",(i,f,c)=>{let t=i(f,c),{abortEarly:r}=y(c);if(t.success===false)return t;let a=[],n=[];for(let u=0;u<t.data.length;u++){let p=e._parse(t.data[u],c);if(p.success)a.push(p.data);else {if(p=p,r!==false){let m=d(p.error,u);return {success:false,error:m,errors:[m]}}b(p,n,u);}}return n.length>0?{success:false,error:n[0],errors:n}:{success:true,data:a}}),o},any(){return l(()=>true)},preprocess(e,s){return h(s,"_parse",(o,i)=>(i=e(i),o(i))),s},union(e,s){return l(c=>{for(let t=0;t<e.length;t++){let r=e[t]._parse(c);if(r.success)return r}return false},{message:c=>`Invalid union value. Expected the value to match one of the schemas:${e.map((t,r)=>` ${r+1}. ${t._getDescription()}`).join(",")} but received "${typeof c}" with value: ${g(c)?JSON.stringify(c):`"${c}"`}`,...s,type:"union"})}};function O(e){return s=>`The value "${s}" must be type of ${e} but is type of "${typeof s}".`}function h(e,s,o){let i=e[s];e[s]=(...f)=>o(i,...f);}function l(e,{type:s="any",name:o,message:i}={}){i=i||O(s);let f={name:o,message:i,type:s},c={_getName(){return o},_getType(){return s},_getDescription(){return this._getName()??this._getType()},_parse(t,r){let a=e(t);if(a===true)return {success:true,data:t};if(typeof a=="object"&&a?.success===true)return a;let n={message:typeof i=="function"?i(t):i};return {success:false,error:n,errors:[n]}},parse(t,r){let a=c._parse(t,r);if(!a.success)throw a=a,new Error(a.error.message,{cause:a.error.cause});return a.data},safeParse(t,r){return c._parse(t,r)},transform(t){return h(this,"_parse",(r,a,n)=>{let u=r(a,n);return u.success&&(u.data=t(u.data)),u}),this},optional(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r===void 0&&(n.data=void 0,n.success=true),n}),this},nullable(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r===null&&(n.data=null,n.success=true),n}),this},nullish(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r==null&&(n.success=true,n.data=r),n}),this},default(t){return h(this,"_parse",(r,a,n)=>(a===void 0&&(a=t,a=typeof t=="function"?t():t),r(a,n))),this},pipe(t){return h(this,"_parse",(r,a,n)=>{let u=r(a,n);return u.success?t._parse(u.data,n):u}),this},refine(t,{message:r,type:a}={}){return a&&(r=r||O(a),s=a),h(this,"_parse",(n,u,p)=>{let m=n(u,p);y(p);if(!m.success)return m;let I=t(m.data);if(I===true||typeof I=="object"&&I?.success===true)return m;let T={message:typeof r=="function"?r(u):r};return {success:false,error:T,errors:[T]}}),this}};return S.length>0?S.reduce((t,r)=>r(t,e,f)??t,c):c}var S=[];function $(e){S.push(e);}export{R as a,h as b,$ as c};
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});
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});
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';
export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
import'./chunk-SHVCROKM.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
import'./chunk-BV6SWQSH.mjs';export{c as extend,b as hookOriginal,a as s}from'./chunk-NCHMO7B3.mjs';
+8
-8
{
"name": "@esmj/schema",
"version": "0.5.0",
"version": "0.5.1",
"description": "Tiny extendable package for schema validation.",

@@ -23,4 +23,4 @@ "type": "module",

],
"main": "dist/index",
"module": "dist/index",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"exports": {

@@ -30,3 +30,3 @@ ".": {

"import": "./dist/index.mjs",
"require": "./dist/index.js"
"require": "./dist/index.cjs"
},

@@ -36,3 +36,3 @@ "./full": {

"import": "./dist/full.mjs",
"require": "./dist/full.js"
"require": "./dist/full.cjs"
},

@@ -42,3 +42,3 @@ "./string": {

"import": "./dist/string.mjs",
"require": "./dist/string.js"
"require": "./dist/string.cjs"
},

@@ -48,3 +48,3 @@ "./number": {

"import": "./dist/number.mjs",
"require": "./dist/number.js"
"require": "./dist/number.cjs"
},

@@ -54,3 +54,3 @@ "./array": {

"import": "./dist/array.mjs",
"require": "./dist/array.js"
"require": "./dist/array.cjs"
}

@@ -57,0 +57,0 @@ },

import'./chunk-JFGD5PND.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
var P={abortEarly:true};function d(e,s){if(!s)return e;let o=e?.cause?.key?`${s}.${e.cause.key}`:`${s}`;return {message:`Error parsing key "${o}": ${e.message}`,cause:{key:o}}}function b(e,s,o){!e.errors||e.errors.length===0||e.errors.forEach(i=>{let f=d(i,o);s.push(f);});}function y(e){return {...P,...e}}var x=e=>typeof e=="string"||e instanceof String,k=e=>typeof e=="number"||e instanceof Number,w=e=>e===true||e===false,E=e=>e instanceof Date&&!Number.isNaN(e.getTime()),_=e=>Array.isArray(e),g=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),R={object(e,s){let o=l(g,{...s,type:"object"});return o._getDescription=()=>`object({ ${Object.entries(e).map(([f,c])=>`${f}: ${c._getDescription()}`).join(", ")} })`,h(o,"_parse",(i,f,c)=>{let t=i(f,c),{abortEarly:r}=y(c);if(t.success===false)return t;let a={},n=[];for(let u in e){let p=e[u]._parse(t.data[u],c);if(p.success)a[u]=p.data;else {if(p=p,r!==false){let m=d(p.error,u);return {success:false,error:m,errors:[m]}}b(p,n,u);}}return n.length>0?{success:false,error:n[0],errors:n}:{success:true,data:a}}),o},string(e){return l(x,{...e,type:"string"})},number(e){return l(k,{...e,type:"number"})},boolean(e){return l(w,{...e,type:"boolean"})},date(e){return l(E,{...e,type:"date"})},enum(e,s){let o=t=>e.includes(t),i=t=>`Invalid ${f} value. Expected ${e.map(r=>`"${r}"`).join(" | ")}, received "${t}".`,f="enum",c=l(o,{message:i,...s,type:f});return c._getDescription=()=>`enum(${e.map(t=>`"${t}"`).join(" | ")})`,c},array(e,s){let o=l(_,{...s,type:"array"});return o._getDescription=()=>`array(${e._getDescription()})`,h(o,"_parse",(i,f,c)=>{let t=i(f,c),{abortEarly:r}=y(c);if(t.success===false)return t;let a=[],n=[];for(let u=0;u<t.data.length;u++){let p=e._parse(t.data[u],c);if(p.success)a.push(p.data);else {if(p=p,r!==false){let m=d(p.error,u);return {success:false,error:m,errors:[m]}}b(p,n,u);}}return n.length>0?{success:false,error:n[0],errors:n}:{success:true,data:a}}),o},any(){return l(()=>true)},preprocess(e,s){return h(s,"_parse",(o,i)=>(i=e(i),o(i))),s},union(e,s){return l(c=>{for(let t=0;t<e.length;t++){let r=e[t]._parse(c);if(r.success)return r}return false},{message:c=>`Invalid union value. Expected the value to match one of the schemas:${e.map((t,r)=>` ${r+1}. ${t._getDescription()}`).join(",")} but received "${typeof c}" with value: ${g(c)?JSON.stringify(c):`"${c}"`}`,...s,type:"union"})}};function O(e){return s=>`The value "${s}" must be type of ${e} but is type of "${typeof s}".`}function h(e,s,o){let i=e[s];e[s]=(...f)=>o(i,...f);}function l(e,{type:s="any",name:o,message:i}={}){i=i||O(s);let f={name:o,message:i,type:s},c={_getName(){return o},_getType(){return s},_getDescription(){return this._getName()??this._getType()},_parse(t,r){let a=e(t);if(a===true)return {success:true,data:t};if(typeof a=="object"&&a?.success===true)return a;let n={message:typeof i=="function"?i(t):i};return {success:false,error:n,errors:[n]}},parse(t,r){let a=c._parse(t,r);if(!a.success)throw a=a,new Error(a.error.message,{cause:a.error.cause});return a.data},safeParse(t,r){return c._parse(t,r)},transform(t){return h(this,"_parse",(r,a,n)=>{let u=r(a,n);return u.success&&(u.data=t(u.data)),u}),this},optional(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r===void 0&&(n.data=void 0,n.success=true),n}),this},nullable(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r===null&&(n.data=null,n.success=true),n}),this},nullish(){return h(this,"_parse",(t,r,a)=>{let n=t(r,a);return !n.success&&r==null&&(n.success=true,n.data=r),n}),this},default(t){return h(this,"_parse",(r,a,n)=>(a===void 0&&(a=t,a=typeof t=="function"?t():t),r(a,n))),this},pipe(t){return h(this,"_parse",(r,a,n)=>{let u=r(a,n);return u.success?t._parse(u.data,n):u}),this},refine(t,{message:r,type:a}={}){return a&&(r=r||O(a),s=a),h(this,"_parse",(n,u,p)=>{let m=n(u,p);y(p);if(!m.success)return m;let I=t(m.data);if(I===true||typeof I=="object"&&I?.success===true)return m;let T={message:typeof r=="function"?r(u):r};return {success:false,error:T,errors:[T]}}),this}};return S.length>0?S.reduce((t,r)=>r(t,e,f)??t,c):c}var S=[];function $(e){S.push(e);}export{R as a,h as b,$ as c};
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});
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});
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});
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';
export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
import'./chunk-QEBUM44M.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
import'./chunk-6ABUMTDR.js';export{c as extend,b as hookOriginal,a as s}from'./chunk-5ARMWSHU.js';
import { s } from '../src/full.ts';
// Advanced form validation example
const addressSchema = s.object({
street: s.string().min(3).max(100),
city: s.string().min(2).max(50),
zipCode: s.string().length(5).refine((val) => /^\d{5}$/.test(val), {
message: 'ZIP code must be 5 digits',
}),
country: s.enum(['US', 'CA', 'MX', 'UK']),
});
const userProfileSchema = s.object({
// Personal info
firstName: s.string().trim().min(2).max(50),
lastName: s.string().trim().min(2).max(50),
email: s
.string()
.trim()
.toLowerCase()
.refine((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), {
message: 'Invalid email address',
}),
// Contact
phone: s
.string()
.optional()
.transform((val) => val?.replace(/\D/g, ''))
.refine((val) => !val || val.length === 10, {
message: 'Phone number must be 10 digits',
}),
// Address
address: addressSchema.optional(),
// Preferences
role: s.enum(['admin', 'editor', 'viewer']).default('viewer'),
tags: s.array(s.string()).min(1).max(5).unique(),
isActive: s.boolean().default(true),
// Metadata
createdAt: s.date(),
updatedAt: s.date().optional(),
});
console.log('=== Valid User Profile ===');
const validProfile = {
firstName: ' John ',
lastName: 'Doe',
email: ' JOHN.DOE@EXAMPLE.COM ',
phone: '(555) 123-4567',
address: {
street: '123 Main St',
city: 'New York',
zipCode: '10001',
country: 'US' as const,
},
role: 'admin' as const,
tags: ['developer', 'typescript', 'node'],
isActive: true,
createdAt: new Date(),
};
console.log('Input:', validProfile);
console.log('Parsed:', userProfileSchema.parse(validProfile));
console.log('\n=== Invalid User Profile (missing required fields) ===');
const invalidProfile = {
firstName: 'John',
// lastName missing
email: 'invalid-email',
tags: [],
createdAt: new Date(),
};
console.log('Result:', userProfileSchema.safeParse(invalidProfile));
console.log('\n=== Invalid ZIP Code ===');
const invalidZipProfile = {
...validProfile,
address: {
street: '123 Main St',
city: 'New York',
zipCode: 'ABC12', // Invalid: not digits
country: 'US' as const,
},
};
console.log('Result:', userProfileSchema.safeParse(invalidZipProfile));
// API response validation
const apiResponseSchema = s.object({
status: s.enum(['success', 'error']),
data: s
.object({
users: s.array(
s.object({
id: s.number().positive().int(),
name: s.string(),
email: s.string(),
}),
),
total: s.number().positive().int(),
})
.optional(),
error: s
.object({
code: s.string(),
message: s.string(),
})
.optional(),
});
console.log('\n=== API Response Validation (Success) ===');
const successResponse = {
status: 'success' as const,
data: {
users: [
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' },
],
total: 2,
},
};
console.log('Result:', apiResponseSchema.parse(successResponse));
console.log('\n=== API Response Validation (Error) ===');
const errorResponse = {
status: 'error' as const,
error: {
code: 'NOT_FOUND',
message: 'User not found',
},
};
console.log('Result:', apiResponseSchema.parse(errorResponse));
import { s } from '../src/full.ts';
// String validations with transformations
console.log('=== String Validations ===');
console.log(
'trim + startsWith + endsWith:',
s
.string()
.trim()
.startsWith('Hello')
.endsWith('World')
.safeParse(' Hello, World '),
);
console.log(
'startsWith + endsWith (without trim):',
s.string().startsWith('Hello').endsWith('World').safeParse(' Hello, World '),
);
// Array validations
console.log('\n=== Array Validations ===');
console.log(
'Array with min/max:',
s.array(s.string()).min(2).max(5).safeParse(['Hello', 'World']),
);
// Number validations
console.log('\n=== Number Validations ===');
console.log('Integer + positive:', s.number().int().positive().safeParse(42));
console.log('Float validation:', s.number().float().safeParse(3.14));
// Union with extended methods
console.log('\n=== Union Validations ===');
console.log(
'Union with string validation:',
s
.union([
s.string({ message: 'stringSchema' }).startsWith('Hello'),
s.number(),
])
.safeParse('World'),
);
import { s, extend, type StringSchemaInterface } from '../src/index.ts';
// Extend StringSchemaInterface to add custom methods
declare module '../src/index.ts' {
interface StringSchemaInterface {
email(options?: { message?: string }): StringSchemaInterface;
url(options?: { message?: string }): StringSchemaInterface;
uuid(options?: { message?: string }): StringSchemaInterface;
}
}
// Implement the extensions
extend((schema, _, options) => {
if (options?.type === 'string') {
const stringSchema = schema as StringSchemaInterface;
// Email validation
stringSchema.email = function ({ message } = {}) {
return this.refine(
(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
{
message: message || ((value: string) => `"${value}" is not a valid email address`),
},
);
};
// URL validation
stringSchema.url = function ({ message } = {}) {
return this.refine(
(value) => {
try {
new URL(value);
return true;
} catch {
return false;
}
},
{
message: message || ((value: string) => `"${value}" is not a valid URL`),
},
);
};
// UUID validation
stringSchema.uuid = function ({ message } = {}) {
return this.refine(
(value) =>
/^[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(
value,
),
{
message: message || ((value: string) => `"${value}" is not a valid UUID`),
},
);
};
}
return schema;
});
// Now use the extended schema
console.log('=== Email Validation ===');
const emailSchema = s.string().email();
console.log('Valid email:', emailSchema.safeParse('user@example.com'));
console.log('Invalid email:', emailSchema.safeParse('not-an-email'));
console.log('Empty string:', emailSchema.safeParse(''));
console.log('\n=== URL Validation ===');
const urlSchema = s.string().url();
console.log('Valid URL:', urlSchema.safeParse('https://example.com'));
console.log('Valid URL with path:', urlSchema.safeParse('https://example.com/path'));
console.log('Invalid URL:', urlSchema.safeParse('not a url'));
console.log('\n=== UUID Validation ===');
const uuidSchema = s.string().uuid();
console.log(
'Valid UUID:',
uuidSchema.safeParse('550e8400-e29b-41d4-a716-446655440000'),
);
console.log('Invalid UUID:', uuidSchema.safeParse('not-a-uuid'));
console.log(
'Invalid UUID format:',
uuidSchema.safeParse('550e8400-e29b-41d4-a716'),
);
// Combine extensions in a schema
console.log('\n=== Combined Schema ===');
const userSchema = s.object({
id: s.string().uuid(),
email: s.string().trim().toLowerCase().email(),
website: s.string().url().optional(),
});
console.log(
'Valid user:',
userSchema.parse({
id: '550e8400-e29b-41d4-a716-446655440000',
email: ' USER@EXAMPLE.COM ',
website: 'https://example.com',
}),
);
console.log(
'\nInvalid user (bad email):',
userSchema.safeParse({
id: '550e8400-e29b-41d4-a716-446655440000',
email: 'not-an-email',
}),
);
// Custom error messages
console.log('\n=== Custom Error Messages ===');
const customEmailSchema = s
.string()
.email({ message: 'Please enter a valid email address' });
console.log(
'Custom error:',
customEmailSchema.safeParse('invalid'),
);
import { s } from '../src/full.ts';
// Custom email validation using refine
const emailSchema = s
.string()
.trim()
.toLowerCase()
.refine((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), {
message: 'Invalid email address format',
});
console.log('=== Custom Email Validation ===');
console.log('Valid email:', emailSchema.safeParse('user@example.com'));
console.log('Invalid email:', emailSchema.safeParse('not-an-email'));
console.log(
'Email with whitespace:',
emailSchema.safeParse(' User@Example.COM '),
);
// Custom URL validation
const urlSchema = s.string().refine(
(value) => {
try {
new URL(value);
return true;
} catch {
return false;
}
},
{
message: (value) => `"${value}" is not a valid URL`,
},
);
console.log('\n=== Custom URL Validation ===');
console.log('Valid URL:', urlSchema.safeParse('https://example.com'));
console.log('Invalid URL:', urlSchema.safeParse('not a url'));
// Custom age validation
const ageSchema = s
.number()
.int()
.positive()
.refine((value) => value >= 18, {
message: (value) =>
`Age must be at least 18 (received ${value} years old)`,
})
.refine((value) => value <= 120, {
message: (value) => `Age seems unrealistic (received ${value} years old)`,
});
console.log('\n=== Custom Age Validation ===');
console.log('Valid age:', ageSchema.safeParse(25));
console.log('Too young:', ageSchema.safeParse(15));
console.log('Too old:', ageSchema.safeParse(150));
// Custom password validation
const passwordSchema = s
.string()
.min(8, { message: 'Password must be at least 8 characters' })
.refine((value) => /[A-Z]/.test(value), {
message: 'Password must contain at least one uppercase letter',
})
.refine((value) => /[a-z]/.test(value), {
message: 'Password must contain at least one lowercase letter',
})
.refine((value) => /[0-9]/.test(value), {
message: 'Password must contain at least one number',
})
.refine((value) => /[^A-Za-z0-9]/.test(value), {
message: 'Password must contain at least one special character',
});
console.log('\n=== Custom Password Validation ===');
console.log('Valid password:', passwordSchema.safeParse('MyP@ssw0rd'));
console.log('Too short:', passwordSchema.safeParse('Pass1!'));
console.log('No uppercase:', passwordSchema.safeParse('myp@ssw0rd'));
console.log('No special char:', passwordSchema.safeParse('MyPassw0rd'));
// Custom object validation with cross-field checks
const registrationSchema = s
.object({
password: s.string().min(8),
confirmPassword: s.string(),
email: emailSchema,
age: ageSchema,
})
.refine((data) => data.password === data.confirmPassword, {
message: 'Passwords do not match',
});
console.log('\n=== Cross-Field Validation ===');
console.log(
'Valid registration:',
registrationSchema.safeParse({
password: 'MyP@ssw0rd',
confirmPassword: 'MyP@ssw0rd',
email: 'user@example.com',
age: 25,
}),
);
console.log(
'Password mismatch:',
registrationSchema.safeParse({
password: 'MyP@ssw0rd',
confirmPassword: 'Different123!',
email: 'user@example.com',
age: 25,
}),
);
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"moduleResolution": "node",
"esModuleInterop": true,
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"noEmit": true
},
"include": ["src/**/*"]
}