@esmj/schema 0.1.1 → 0.2.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/README.md +62 -6
- package/dist/index.d.mts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +13 -7
package/README.md
CHANGED
|
@@ -24,11 +24,50 @@ When choosing a schema validation library, bundle size can be an important facto
|
|
|
24
24
|
|
|
25
25
|
| Library | Bundle Size (minified + gzipped) |
|
|
26
26
|
|------------------|---------------------------------|
|
|
27
|
-
| `@esmj/schema` |
|
|
28
|
-
| Superstruct | ~3
|
|
29
|
-
| Yup | ~12
|
|
30
|
-
| Zod
|
|
31
|
-
|
|
|
27
|
+
| `@esmj/schema` | `~1 KB` |
|
|
28
|
+
| Superstruct | ~3.2 KB |
|
|
29
|
+
| Yup | ~12.2 KB |
|
|
30
|
+
| Zod@3 | ~13 KB |
|
|
31
|
+
| @zod/mini | ~20,5 KB |
|
|
32
|
+
| Joi | ~40,4 KB |
|
|
33
|
+
| Zod@4 | ~40,8 KB |
|
|
34
|
+
|
|
35
|
+
### Performance Comparison
|
|
36
|
+
|
|
37
|
+
#### Schema Creation Performance
|
|
38
|
+
|
|
39
|
+
| Library | 1 Schema | 1,000 Schema | 1,000,000 Schema |
|
|
40
|
+
|-----------------|-------------|------------------|----------------------|
|
|
41
|
+
| `@esmj/schema` | `0.02 ms` | 4.93 ms | `399.62 ms` |
|
|
42
|
+
| zod@3 | 0.08 ms | 9.68 ms | 8.53 s |
|
|
43
|
+
| @zod/mini | 0.22 ms | 39.77 ms | 34.51 s |
|
|
44
|
+
| Yup | 0.54 ms | 14.03 ms | 12.34 s |
|
|
45
|
+
| Superstruct | 0.13 ms | `1.04 ms` | 487.94 ms |
|
|
46
|
+
| Joi | 0.62 ms | 31.60 ms | 23.06 s |
|
|
47
|
+
|
|
48
|
+
#### Parsing Performance
|
|
49
|
+
|
|
50
|
+
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
51
|
+
|-----------------|-------------|------------------|----------------------|
|
|
52
|
+
| `@esmj/schema` | `0.05 ms` | 0.46 ms | 267.93 ms |
|
|
53
|
+
| zod@3 | 0.14 ms | 1.44 ms | 897.89 ms |
|
|
54
|
+
| @zod/mini | 0.23 ms | `0.42 ms` | `199.08 ms` |
|
|
55
|
+
| Yup | 0.30 ms | 9.49 ms | 8.69 s |
|
|
56
|
+
| Superstruct | 0.08 ms | 4.18 ms | 3.71 s |
|
|
57
|
+
| Joi | 0.33 ms | 3.35 ms | 2.69 s |
|
|
58
|
+
|
|
59
|
+
#### Error Handling Performance
|
|
60
|
+
|
|
61
|
+
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
62
|
+
|-----------------|-------------|------------------|----------------------|
|
|
63
|
+
| `@esmj/schema` | `0.03 ms` | `0.59 ms` | `365.32 ms` |
|
|
64
|
+
| zod3 | 0.05 ms | 2.09 ms | 1.26 s |
|
|
65
|
+
| @zod/mini | 0.07 ms | 0.99 ms | 545.12 ms |
|
|
66
|
+
| Yup | 0.27 ms | 19.28 ms | 18.87 s |
|
|
67
|
+
| Superstruct | 0.04 ms | 8.62 ms | 6.24 s |
|
|
68
|
+
| Joi | 0.15 ms | 4.13 ms | 2.57 s |
|
|
69
|
+
|
|
70
|
+
**Note:** During the performance tests, `@zod/mini` was observed to consume 200% CPU, while other libraries used only 100% CPU. This may affect the interpretation of the results, especially in multi-threaded environments.
|
|
32
71
|
|
|
33
72
|
## Usage
|
|
34
73
|
|
|
@@ -180,9 +219,26 @@ const result = stringSchema.parse('hello');
|
|
|
180
219
|
Safely parses the given value according to the schema, returning a success or error result.
|
|
181
220
|
|
|
182
221
|
```typescript
|
|
183
|
-
const result = stringSchema.safeParse('hello');
|
|
222
|
+
const result = stringSchema.safeParse('hello');
|
|
223
|
+
// { success: true, data: 'hello' }
|
|
224
|
+
|
|
225
|
+
const errorResult = stringSchema.safeParse(123);
|
|
226
|
+
// { success: false, error: { message: 'The value "123" must be type of string but is type of "number".' } }
|
|
184
227
|
```
|
|
185
228
|
|
|
229
|
+
**Note:** The `error` returned by `safeParse` is not a native `Error` instance. Instead, it is a plain object with the following structure:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
type ErrorStructure = {
|
|
233
|
+
message: string;
|
|
234
|
+
cause?: {
|
|
235
|
+
key?: string;
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This allows for easier serialization and debugging but may require additional handling if you expect a native `Error` instance.
|
|
241
|
+
|
|
186
242
|
#### `optional()`
|
|
187
243
|
|
|
188
244
|
Makes the schema optional.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
type ErrorStructure = {
|
|
2
|
+
message: string;
|
|
3
|
+
cause?: {
|
|
4
|
+
key?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
type Valid<Output> = {
|
|
8
|
+
success: true;
|
|
9
|
+
data: Output;
|
|
10
|
+
};
|
|
11
|
+
type Invalid = {
|
|
12
|
+
success: false;
|
|
13
|
+
error: ErrorStructure;
|
|
14
|
+
};
|
|
15
|
+
type InternalParseOutput<Output> = Valid<Output> | Invalid;
|
|
1
16
|
interface SchemaInterface<Input, Output> {
|
|
17
|
+
_parse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
2
18
|
parse(value: Input | Partial<Input> | unknown): Output;
|
|
3
|
-
safeParse(value: Input | Partial<Input> | unknown):
|
|
4
|
-
success: true;
|
|
5
|
-
data: Output;
|
|
6
|
-
} | {
|
|
7
|
-
success: false;
|
|
8
|
-
error: Error;
|
|
9
|
-
};
|
|
19
|
+
safeParse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
10
20
|
optional(): SchemaInterface<Input, Partial<Output> | undefined>;
|
|
11
21
|
transform<NewOutput>(callback: (value: Input) => NewOutput): SchemaInterface<Input, NewOutput>;
|
|
12
22
|
nullable(): SchemaInterface<Input, Output | null>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
type ErrorStructure = {
|
|
2
|
+
message: string;
|
|
3
|
+
cause?: {
|
|
4
|
+
key?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
type Valid<Output> = {
|
|
8
|
+
success: true;
|
|
9
|
+
data: Output;
|
|
10
|
+
};
|
|
11
|
+
type Invalid = {
|
|
12
|
+
success: false;
|
|
13
|
+
error: ErrorStructure;
|
|
14
|
+
};
|
|
15
|
+
type InternalParseOutput<Output> = Valid<Output> | Invalid;
|
|
1
16
|
interface SchemaInterface<Input, Output> {
|
|
17
|
+
_parse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
2
18
|
parse(value: Input | Partial<Input> | unknown): Output;
|
|
3
|
-
safeParse(value: Input | Partial<Input> | unknown):
|
|
4
|
-
success: true;
|
|
5
|
-
data: Output;
|
|
6
|
-
} | {
|
|
7
|
-
success: false;
|
|
8
|
-
error: Error;
|
|
9
|
-
};
|
|
19
|
+
safeParse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
10
20
|
optional(): SchemaInterface<Input, Partial<Output> | undefined>;
|
|
11
21
|
transform<NewOutput>(callback: (value: Input) => NewOutput): SchemaInterface<Input, NewOutput>;
|
|
12
22
|
nullable(): SchemaInterface<Input, Output | null>;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var y=
|
|
1
|
+
'use strict';var h=r=>typeof r=="string"||r instanceof String,I=r=>typeof r=="number"||r instanceof Number,l=r=>r===true||r===false,y=r=>r instanceof Date&&!Number.isNaN(r.getTime()),d=r=>Array.isArray(r),S=r=>typeof r=="object"&&r!==null&&!Array.isArray(r),g={object(r){let a=p(S,{type:"object"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n={};for(let t in r){let e=r[t]._parse(c.data[t]);if(e.success)n[t]=e.data;else {e=e;let s=e?.error?.cause?.key?`${t}.${e?.error?.cause?.key}`:t;return e.error.message=`Error parsing key "${s}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},string(){return p(h,{type:"string"})},number(){return p(I,{type:"number"})},boolean(){return p(l,{type:"boolean"})},date(){return p(y,{type:"date"})},enum(r){let a=n=>r.includes(n),u=n=>`Invalid ${o} value. Expected ${r.map(t=>`"${t}"`).join(" | ")}, received "${n}".`,o="enum";return p(a,{type:o,message:u})},array(r){let a=p(d,{type:"array"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n=[];for(let t=0;t<c.data.length;t++){let e=r._parse(c.data[t]);if(e.success)n.push(e.data);else {e=e;let s=e.error?.cause?.key?`${t}.${e.error.cause.key}`:`${t}`;return e.error.message=`Error parsing index "${t}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},any(){return p(()=>true)},preprocess(r,a){return i(a,"_parse",(u,o)=>(o=r(o),u(o))),a}};function b(r){return a=>`The value "${a}" must be type of ${r} but is type of "${typeof a}".`}function i(r,a,u){let o=r[a];r[a]=(...c)=>u(o,...c);}function p(r,{type:a="any",message:u}={}){u=u||b(a);let o={message:u,type:a},c={_parse(n){return r(n)?{success:true,data:n}:{success:false,error:{message:u(n)}}},parse(n){let t=c._parse(n);if(!t.success)throw t=t,new Error(t.error.message,{cause:t.error.cause});return t.data},safeParse(n){return c._parse(n)},transform(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success&&(s.data=n(s.data)),s}),this},optional(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=void 0,e.success=true),e}),this},nullable(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=null,e.success=true),e}),this},nullish(){return i(this,"_parse",(n,t)=>{let e=n(t);return !e.success&&t==null&&(e.success=true,e.data=t),e}),this},default(n){return i(this,"_parse",(t,e)=>(e===void 0&&(e=n,e=typeof n=="function"?n():n),t(e))),this},pipe(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success?n._parse(s.data):s}),this},refine(n,{message:t}){return i(this,"_parse",(e,s)=>{let m=e(s);return n(m.data)?m:{success:false,error:{message:t}}}),this}};return f.length>0?f.reduce((n,t)=>t(n,r,o)??n,c):c}var f=[];function T(r){f.push(r);}exports.extend=T;exports.s=g;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y=
|
|
1
|
+
var h=r=>typeof r=="string"||r instanceof String,I=r=>typeof r=="number"||r instanceof Number,l=r=>r===true||r===false,y=r=>r instanceof Date&&!Number.isNaN(r.getTime()),d=r=>Array.isArray(r),S=r=>typeof r=="object"&&r!==null&&!Array.isArray(r),g={object(r){let a=p(S,{type:"object"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n={};for(let t in r){let e=r[t]._parse(c.data[t]);if(e.success)n[t]=e.data;else {e=e;let s=e?.error?.cause?.key?`${t}.${e?.error?.cause?.key}`:t;return e.error.message=`Error parsing key "${s}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},string(){return p(h,{type:"string"})},number(){return p(I,{type:"number"})},boolean(){return p(l,{type:"boolean"})},date(){return p(y,{type:"date"})},enum(r){let a=n=>r.includes(n),u=n=>`Invalid ${o} value. Expected ${r.map(t=>`"${t}"`).join(" | ")}, received "${n}".`,o="enum";return p(a,{type:o,message:u})},array(r){let a=p(d,{type:"array"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n=[];for(let t=0;t<c.data.length;t++){let e=r._parse(c.data[t]);if(e.success)n.push(e.data);else {e=e;let s=e.error?.cause?.key?`${t}.${e.error.cause.key}`:`${t}`;return e.error.message=`Error parsing index "${t}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},any(){return p(()=>true)},preprocess(r,a){return i(a,"_parse",(u,o)=>(o=r(o),u(o))),a}};function b(r){return a=>`The value "${a}" must be type of ${r} but is type of "${typeof a}".`}function i(r,a,u){let o=r[a];r[a]=(...c)=>u(o,...c);}function p(r,{type:a="any",message:u}={}){u=u||b(a);let o={message:u,type:a},c={_parse(n){return r(n)?{success:true,data:n}:{success:false,error:{message:u(n)}}},parse(n){let t=c._parse(n);if(!t.success)throw t=t,new Error(t.error.message,{cause:t.error.cause});return t.data},safeParse(n){return c._parse(n)},transform(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success&&(s.data=n(s.data)),s}),this},optional(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=void 0,e.success=true),e}),this},nullable(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=null,e.success=true),e}),this},nullish(){return i(this,"_parse",(n,t)=>{let e=n(t);return !e.success&&t==null&&(e.success=true,e.data=t),e}),this},default(n){return i(this,"_parse",(t,e)=>(e===void 0&&(e=n,e=typeof n=="function"?n():n),t(e))),this},pipe(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success?n._parse(s.data):s}),this},refine(n,{message:t}){return i(this,"_parse",(e,s)=>{let m=e(s);return n(m.data)?m:{success:false,error:{message:t}}}),this}};return f.length>0?f.reduce((n,t)=>t(n,r,o)??n,c):c}var f=[];function T(r){f.push(r);}export{T as extend,g as s};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmj/schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Tiny extendable package for schema validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"lint": "biome check --no-errors-on-unmatched",
|
|
24
24
|
"lint:fix": "npm run lint -- --fix --unsafe",
|
|
25
|
+
"benchmark": "node benchmark/benchmark.ts",
|
|
25
26
|
"dev": "node_modules/.bin/tsup --dts --watch --onSuccess 'node ./dist/index.mjs'",
|
|
26
27
|
"test": "node --test --experimental-strip-types",
|
|
27
28
|
"test:watch": "npm run test -- --watch",
|
|
@@ -62,17 +63,22 @@
|
|
|
62
63
|
"homepage": "https://github.com/mjancarik/esmj-schema#readme",
|
|
63
64
|
"devDependencies": {
|
|
64
65
|
"@biomejs/biome": "1.9.4",
|
|
65
|
-
"@commitlint/cli": "^19.8.
|
|
66
|
-
"@commitlint/config-conventional": "^19.8.
|
|
67
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
68
|
-
"@typescript-eslint/parser": "^8.
|
|
66
|
+
"@commitlint/cli": "^19.8.1",
|
|
67
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
|
69
|
+
"@typescript-eslint/parser": "^8.33.0",
|
|
70
|
+
"@zod/mini": "^4.0.0-beta.0",
|
|
69
71
|
"commitizen": "^4.3.1",
|
|
70
72
|
"conventional-changelog-cli": "^5.0.0",
|
|
71
73
|
"cz-conventional-changelog": "^3.3.0",
|
|
72
74
|
"git-cz": "^4.9.0",
|
|
73
75
|
"husky": "^9.1.7",
|
|
74
|
-
"
|
|
76
|
+
"joi": "^17.13.3",
|
|
77
|
+
"lint-staged": "^16.1.0",
|
|
75
78
|
"prettier": "^3.5.3",
|
|
76
|
-
"
|
|
79
|
+
"superstruct": "^2.0.2",
|
|
80
|
+
"tsup": "^8.5.0",
|
|
81
|
+
"yup": "^1.6.1",
|
|
82
|
+
"zod": "^3.25.42"
|
|
77
83
|
}
|
|
78
84
|
}
|