@oxog/vld 2.1.0 → 2.2.7

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.
Files changed (228) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +413 -1235
  3. package/dist/chunks/errors-core-CerMg2rq.js +1 -0
  4. package/dist/chunks/index-CkbfQQ4n.js +1 -0
  5. package/dist/chunks/index-yjpbvFgw.js +1 -0
  6. package/dist/chunks/ip-validation-g5LWgy9t.js +1 -0
  7. package/dist/chunks/security-Dy24T8N7.js +1 -0
  8. package/dist/cjs/chunks/errors-core-DrydF46s.cjs +1 -0
  9. package/dist/cjs/chunks/index-BEV9nG0N.cjs +1 -0
  10. package/dist/cjs/chunks/index-ZjHAxYdA.cjs +1 -0
  11. package/dist/cjs/chunks/ip-validation-BZqPamPC.cjs +1 -0
  12. package/dist/cjs/chunks/security-aXZVI7qW.cjs +1 -0
  13. package/dist/cjs/cli/bin.cjs +1 -505
  14. package/dist/cjs/cli/index.cjs +1 -209
  15. package/dist/cjs/codecs/index.cjs +1 -45
  16. package/dist/cjs/coercion/index.cjs +1 -588
  17. package/dist/cjs/compat/emitter.cjs +1 -184
  18. package/dist/cjs/compat/result.cjs +1 -189
  19. package/dist/cjs/errors.cjs +1 -180
  20. package/dist/cjs/index.cjs +1 -1894
  21. package/dist/cjs/kernel.cjs +1 -415
  22. package/dist/cjs/locales/af.cjs +1 -108
  23. package/dist/cjs/locales/ar.cjs +1 -108
  24. package/dist/cjs/locales/bn.cjs +1 -108
  25. package/dist/cjs/locales/da.cjs +1 -108
  26. package/dist/cjs/locales/de.cjs +1 -108
  27. package/dist/cjs/locales/en.cjs +1 -108
  28. package/dist/cjs/locales/es-MX.cjs +1 -107
  29. package/dist/cjs/locales/es.cjs +1 -96
  30. package/dist/cjs/locales/fi.cjs +1 -108
  31. package/dist/cjs/locales/fr.cjs +1 -96
  32. package/dist/cjs/locales/hi.cjs +1 -108
  33. package/dist/cjs/locales/id.cjs +1 -108
  34. package/dist/cjs/locales/index.cjs +1 -43
  35. package/dist/cjs/locales/it.cjs +1 -108
  36. package/dist/cjs/locales/ja.cjs +1 -108
  37. package/dist/cjs/locales/ko.cjs +1 -108
  38. package/dist/cjs/locales/lazy.cjs +1 -188
  39. package/dist/cjs/locales/nl.cjs +1 -108
  40. package/dist/cjs/locales/no.cjs +1 -108
  41. package/dist/cjs/locales/pl.cjs +1 -108
  42. package/dist/cjs/locales/pt-BR.cjs +1 -108
  43. package/dist/cjs/locales/pt.cjs +1 -108
  44. package/dist/cjs/locales/ru.cjs +1 -108
  45. package/dist/cjs/locales/runtime.cjs +1 -51
  46. package/dist/cjs/locales/sv.cjs +1 -108
  47. package/dist/cjs/locales/sw.cjs +1 -108
  48. package/dist/cjs/locales/th.cjs +1 -108
  49. package/dist/cjs/locales/tr.cjs +1 -108
  50. package/dist/cjs/locales/vi.cjs +1 -108
  51. package/dist/cjs/locales/zh.cjs +1 -108
  52. package/dist/cjs/mini.cjs +1 -242
  53. package/dist/cjs/pigment.cjs +1 -207
  54. package/dist/cjs/plugins/index.cjs +1 -12
  55. package/dist/cjs/registry.cjs +1 -37
  56. package/dist/cjs/v3/index.cjs +1 -425
  57. package/dist/cjs/v4/core/index.cjs +1 -894
  58. package/dist/cjs/v4/index.cjs +1 -425
  59. package/dist/cjs/v4/locales/index.cjs +1 -130
  60. package/dist/cjs/v4/mini/index.cjs +1 -509
  61. package/dist/cjs/v4-mini/index.cjs +1 -532
  62. package/dist/cjs/validators/any.cjs +1 -40
  63. package/dist/cjs/validators/array.cjs +1 -283
  64. package/dist/cjs/validators/base.cjs +1 -887
  65. package/dist/cjs/validators/base64.cjs +1 -73
  66. package/dist/cjs/validators/bigint.cjs +1 -232
  67. package/dist/cjs/validators/boolean.cjs +1 -146
  68. package/dist/cjs/validators/codec.cjs +1 -205
  69. package/dist/cjs/validators/custom.cjs +1 -71
  70. package/dist/cjs/validators/date.cjs +1 -278
  71. package/dist/cjs/validators/discriminated-union.cjs +1 -130
  72. package/dist/cjs/validators/enum.cjs +1 -154
  73. package/dist/cjs/validators/file.cjs +1 -130
  74. package/dist/cjs/validators/function.cjs +1 -63
  75. package/dist/cjs/validators/hex.cjs +1 -70
  76. package/dist/cjs/validators/index.cjs +1 -123
  77. package/dist/cjs/validators/intersection.cjs +1 -120
  78. package/dist/cjs/validators/json.cjs +1 -70
  79. package/dist/cjs/validators/lazy.cjs +1 -53
  80. package/dist/cjs/validators/literal.cjs +1 -64
  81. package/dist/cjs/validators/map.cjs +1 -218
  82. package/dist/cjs/validators/nan.cjs +1 -41
  83. package/dist/cjs/validators/never.cjs +1 -36
  84. package/dist/cjs/validators/null.cjs +1 -43
  85. package/dist/cjs/validators/number.cjs +1 -427
  86. package/dist/cjs/validators/object.cjs +1 -868
  87. package/dist/cjs/validators/promise.cjs +1 -115
  88. package/dist/cjs/validators/record.cjs +1 -262
  89. package/dist/cjs/validators/set.cjs +1 -203
  90. package/dist/cjs/validators/string-bool.cjs +1 -124
  91. package/dist/cjs/validators/string-formats.cjs +1 -168
  92. package/dist/cjs/validators/string.cjs +1 -12
  93. package/dist/cjs/validators/symbol.cjs +1 -62
  94. package/dist/cjs/validators/template-literal.cjs +1 -108
  95. package/dist/cjs/validators/tuple.cjs +1 -187
  96. package/dist/cjs/validators/uint8array.cjs +1 -106
  97. package/dist/cjs/validators/undefined.cjs +1 -43
  98. package/dist/cjs/validators/union.cjs +1 -191
  99. package/dist/cjs/validators/unknown.cjs +1 -40
  100. package/dist/cjs/validators/void.cjs +1 -48
  101. package/dist/cjs/validators/xor.cjs +1 -69
  102. package/dist/cli/bin.js +1 -406
  103. package/dist/cli/index.js +1 -205
  104. package/dist/codecs/index.js +1 -11
  105. package/dist/coercion/index.js +1 -579
  106. package/dist/compat/emitter.js +1 -180
  107. package/dist/compat/result.js +1 -170
  108. package/dist/errors-core.d.ts +32 -2
  109. package/dist/errors.js +1 -171
  110. package/dist/index.d.ts +315 -361
  111. package/dist/index.js +1 -1534
  112. package/dist/kernel.js +1 -409
  113. package/dist/locales/af.js +1 -106
  114. package/dist/locales/ar.js +1 -106
  115. package/dist/locales/bn.js +1 -106
  116. package/dist/locales/da.js +1 -106
  117. package/dist/locales/de.js +1 -106
  118. package/dist/locales/en.js +1 -106
  119. package/dist/locales/es-MX.js +1 -105
  120. package/dist/locales/es.js +1 -94
  121. package/dist/locales/fi.js +1 -106
  122. package/dist/locales/fr.js +1 -94
  123. package/dist/locales/hi.js +1 -106
  124. package/dist/locales/id.js +1 -106
  125. package/dist/locales/index.js +1 -29
  126. package/dist/locales/it.js +1 -106
  127. package/dist/locales/ja.js +1 -106
  128. package/dist/locales/ko.js +1 -106
  129. package/dist/locales/lazy.js +1 -177
  130. package/dist/locales/nl.js +1 -106
  131. package/dist/locales/no.js +1 -106
  132. package/dist/locales/pl.js +1 -106
  133. package/dist/locales/pt-BR.js +1 -106
  134. package/dist/locales/pt.js +1 -106
  135. package/dist/locales/ru.js +1 -106
  136. package/dist/locales/runtime.js +1 -41
  137. package/dist/locales/sv.js +1 -106
  138. package/dist/locales/sw.js +1 -106
  139. package/dist/locales/th.js +1 -106
  140. package/dist/locales/tr.js +1 -106
  141. package/dist/locales/vi.js +1 -106
  142. package/dist/locales/zh.js +1 -106
  143. package/dist/mini.d.ts +3 -3
  144. package/dist/mini.js +1 -156
  145. package/dist/pigment.js +1 -180
  146. package/dist/plugins/index.js +1 -1
  147. package/dist/registry.js +1 -34
  148. package/dist/utils/json-schema.d.ts +10 -1
  149. package/dist/v3/index.js +1 -46
  150. package/dist/v4/core/index.d.ts +28 -16
  151. package/dist/v4/core/index.js +1 -277
  152. package/dist/v4/index.js +1 -50
  153. package/dist/v4/locales/index.d.ts +4 -0
  154. package/dist/v4/locales/index.js +1 -77
  155. package/dist/v4/mini/index.js +1 -47
  156. package/dist/v4-mini/index.d.ts +1 -1
  157. package/dist/v4-mini/index.js +1 -75
  158. package/dist/validators/any.js +1 -37
  159. package/dist/validators/array.d.ts +7 -0
  160. package/dist/validators/array.js +1 -279
  161. package/dist/validators/base.d.ts +210 -17
  162. package/dist/validators/base.js +1 -868
  163. package/dist/validators/base64.js +1 -68
  164. package/dist/validators/bigint.d.ts +7 -0
  165. package/dist/validators/bigint.js +1 -228
  166. package/dist/validators/boolean.js +1 -142
  167. package/dist/validators/codec.js +1 -200
  168. package/dist/validators/custom.d.ts +20 -10
  169. package/dist/validators/custom.js +1 -67
  170. package/dist/validators/date.d.ts +2 -0
  171. package/dist/validators/date.js +1 -274
  172. package/dist/validators/discriminated-union.d.ts +4 -2
  173. package/dist/validators/discriminated-union.js +1 -123
  174. package/dist/validators/enum.d.ts +8 -2
  175. package/dist/validators/enum.js +1 -150
  176. package/dist/validators/file.js +1 -125
  177. package/dist/validators/function.js +1 -58
  178. package/dist/validators/hex.js +1 -65
  179. package/dist/validators/index.d.ts +1 -1
  180. package/dist/validators/index.js +1 -35
  181. package/dist/validators/intersection.js +1 -116
  182. package/dist/validators/json.js +1 -66
  183. package/dist/validators/lazy.js +1 -50
  184. package/dist/validators/literal.d.ts +8 -3
  185. package/dist/validators/literal.js +1 -60
  186. package/dist/validators/map.d.ts +7 -0
  187. package/dist/validators/map.js +1 -214
  188. package/dist/validators/nan.js +1 -38
  189. package/dist/validators/never.js +1 -32
  190. package/dist/validators/null.js +1 -40
  191. package/dist/validators/number.d.ts +25 -1
  192. package/dist/validators/number.js +1 -423
  193. package/dist/validators/object.d.ts +18 -2
  194. package/dist/validators/object.js +1 -864
  195. package/dist/validators/promise.d.ts +6 -7
  196. package/dist/validators/promise.js +1 -111
  197. package/dist/validators/record.d.ts +13 -8
  198. package/dist/validators/record.js +1 -258
  199. package/dist/validators/set.d.ts +5 -0
  200. package/dist/validators/set.js +1 -199
  201. package/dist/validators/string-bool.js +1 -120
  202. package/dist/validators/string-formats.d.ts +58 -62
  203. package/dist/validators/string-formats.js +1 -135
  204. package/dist/validators/string.d.ts +49 -10
  205. package/dist/validators/string.js +1 -4
  206. package/dist/validators/symbol.js +1 -58
  207. package/dist/validators/template-literal.js +1 -103
  208. package/dist/validators/tuple.d.ts +17 -13
  209. package/dist/validators/tuple.js +1 -183
  210. package/dist/validators/uint8array.js +1 -101
  211. package/dist/validators/undefined.js +1 -40
  212. package/dist/validators/union.d.ts +1 -0
  213. package/dist/validators/union.js +1 -187
  214. package/dist/validators/unknown.js +1 -37
  215. package/dist/validators/void.js +1 -44
  216. package/dist/validators/xor.d.ts +2 -2
  217. package/dist/validators/xor.js +1 -66
  218. package/package.json +240 -238
  219. package/dist/chunks/errors-core-BeiFUtZM.js +0 -81
  220. package/dist/chunks/index-0R2ntSud.js +0 -508
  221. package/dist/chunks/index-BvH403Yy.js +0 -88
  222. package/dist/chunks/security-B0Pd_vSY.js +0 -35
  223. package/dist/chunks/string-BJRQod3t.js +0 -530
  224. package/dist/cjs/chunks/errors-core-DWxLFs2f.cjs +0 -83
  225. package/dist/cjs/chunks/index-BkI37108.cjs +0 -538
  226. package/dist/cjs/chunks/index-Cc3bjUMX.cjs +0 -91
  227. package/dist/cjs/chunks/security-Dc3Jh13T.cjs +0 -37
  228. package/dist/cjs/chunks/string-BKZrc4hs.cjs +0 -533
package/README.md CHANGED
@@ -1,1235 +1,413 @@
1
- # VLD - Fast & Lightweight TypeScript Validation Library
2
-
3
- [![NPM Version](https://img.shields.io/npm/v/@oxog/vld.svg)](https://www.npmjs.com/package/@oxog/vld) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) [![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-green.svg)](package.json) [![Test Coverage](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg)](package.json)
4
-
5
- VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScript with **Zod-compatible root and subpath APIs**. Built with performance in mind, it provides a simple and intuitive API while maintaining excellent type inference and 27+ language internationalization support.
6
-
7
- ## Table of Contents
8
-
9
- - [Features](#-features)
10
- - [Performance](#-performance)
11
- - [Installation](#-installation)
12
- - [Quick Start](#-quick-start)
13
- - [API Reference](#-api-reference)
14
- - [Internationalization (i18n)](#-internationalization-i18n)
15
- - [Error Handling & Formatting](#%EF%B8%8F-error-handling--formatting)
16
- - [Advanced Examples](#-advanced-examples)
17
- - [Why VLD?](#-why-vld)
18
- - [Codecs - Bidirectional Transformations](#-codecs---bidirectional-transformations)
19
- - [Plugin System](#-plugin-system)
20
- - [Result Pattern](#-result-pattern)
21
- - [CLI Tools](#-cli-tools)
22
- - [Migrating from Zod](#-migrating-from-zod)
23
- - [Benchmarks](#-benchmarks)
24
- - [Contributing](#-contributing)
25
- - [Links](#-links)
26
-
27
- ## Features
28
-
29
- ### Core Features
30
- - **Blazing Fast**: Optimized for V8 engine with superior performance
31
- - **Type-Safe**: Full TypeScript support with excellent type inference
32
- - **Zero Dependencies**: Lightweight with no external dependencies
33
- - **Tree-Shakeable**: Only import what you need
34
- - **Composable**: Chain validations for complex schemas
35
- - **Advanced Error Formatting**: Tree, pretty, and flatten error utilities
36
- - **Multi-language**: Built-in support for 27+ languages
37
- - **100% Statement / Branch / Line Coverage**: Rigorously tested with 2160 passing tests
38
- - **Release-Gated Performance**: CI guards require VLD to stay faster than the latest stable Zod across runtime, startup, and memory benchmarks
39
- - **Drop-in App Verification**: A real TypeScript fixture is compiled and run once with `zod` and once with built VLD, then normalized runtime output is compared
40
-
41
- ### Advanced Zod-Compatible Features
42
- - **Type Coercion**: `v.coerce.string()`, `v.coerce.number()`, `v.coerce.boolean()`, etc.
43
- - **Advanced Types**: BigInt, Symbol, Tuple, Record, Set, Map validation
44
- - **Intersection Types**: Combine multiple schemas with intelligent merging
45
- - **Custom Validation**: `refine()` for custom predicates and validation logic
46
- - **Data Transformation**: `transform()` for post-validation data transformation
47
- - **Default Values**: `default()` for handling undefined inputs elegantly
48
- - **Fallback Handling**: `catch()` for graceful error recovery
49
- - **Object Utilities**: `pick()`, `omit()`, `extend()` for flexible object schemas
50
-
51
- ### NEW in v2.0.0 - Modular Architecture
52
-
53
- #### Tree-Shakable Mini API
54
- ```typescript
55
- import { string, number, object, optional } from '@oxog/vld/mini';
56
-
57
- const schema = object({
58
- name: string().min(1),
59
- age: optional(number().positive()),
60
- });
61
- ```
62
- - **82% smaller bundles** when using only needed validators
63
- - Individual factory functions for optimal tree-shaking
64
- - Full TypeScript support with identical type inference
65
-
66
- #### Lazy Locale Loading
67
- ```typescript
68
- import { setLocaleAsync } from '@oxog/vld/locales';
69
- await setLocaleAsync('tr'); // Loads Turkish on demand
70
- ```
71
- - **92% bundle reduction** - Only English bundled by default
72
- - `preloadLocales()` for SSR/batch loading
73
- - Full backwards compatibility with `setLocale()`
74
-
75
- #### Dual ESM/CJS Build
76
- - ESM builds for modern bundlers (Vite, esbuild)
77
- - CJS builds for Node.js and legacy environments
78
- - Proper `exports` field with conditional exports
79
-
80
- ### NEW in v1.5.0 - Major Platform Release
81
-
82
- #### Plugin System
83
- - **`definePlugin()`**: Create custom plugins with validators, transforms, and codecs
84
- - **`usePlugin()`**: Register plugins globally
85
- - **Plugin Hooks**: Lifecycle hooks for validation events
86
- - **Custom Validators**: Extend VLD with your own validators
87
-
88
- #### Result Pattern
89
- - **`Ok()`/`Err()`**: Functional error handling
90
- - **`match()`**: Pattern matching on results
91
- - **`map()`/`flatMap()`**: Transform results
92
- - **`tryCatch()`**: Safe function execution
93
- - **`all()`**: Combine multiple results
94
-
95
- #### Event System
96
- - **`createEmitter()`**: Type-safe event emitter
97
- - **`createEventBus()`**: Global event bus
98
- - **Validation Events**: Parse start, success, error, field validation
99
-
100
- #### CLI Tools
101
- - **`vld validate`**: Validate data from command line
102
- - **`vld benchmark`**: Run performance benchmarks
103
- - **Colored Output**: Beautiful terminal output with pigment
104
-
105
- #### New Validators
106
- - **`v.discriminatedUnion()`**: Discriminated union types
107
- - **`v.xor()`**: Exclusive OR validation
108
- - **`v.file()`**: File upload validation
109
- - **`v.function()`**: Function validation
110
- - **`v.custom()`**: Type-safe custom validators
111
- - **`v.json()`**: JSON string validation with schema
112
- - **`v.lazy()`**: Recursive schema support
113
- - **`v.nan()`**: NaN validation
114
- - **`v.null()`**: Null validation
115
- - **`v.undefined()`**: Undefined validation
116
- - **`v.templateLiteral()`**: Template literal types
117
-
118
- #### New String Format Validators
119
- - **`v.hostname()`**: Hostname validation
120
- - **`v.emoji()`**: Emoji validation
121
- - **`v.base64()`/`v.base64url()`**: Base64 format validation
122
- - **`v.hex()`**: Hex string validation
123
- - **`v.jwt()`**: JWT format validation
124
- - **`v.nanoid()`/`v.cuid()`/`v.cuid2()`/`v.ulid()`**: ID format validation
125
- - **`v.mac()`**: MAC address validation
126
- - **`v.cidrv4()`/`v.cidrv6()`**: CIDR block validation
127
- - **`v.e164()`**: E.164 phone number validation
128
- - **`v.hash()`**: Hash validation (md5, sha1, sha256, sha384, sha512)
129
- - **`v.iso.date()`/`v.iso.time()`/`v.iso.dateTime()`/`v.iso.duration()`**: ISO format validation
130
-
131
- #### Enhanced Object Utilities
132
- - **`v.strictObject()`**: Strict mode object validation
133
- - **`v.looseObject()`**: Passthrough object validation
134
- - **`v.partialRecord()`**: Partial record validation
135
- - **`v.looseRecord()`**: Loose record validation
136
- - **`v.int()`**: Integer shortcut
137
- - **`v.int32()`**: 32-bit integer shortcut
138
- - **`v.nullish()`**: Null or undefined
139
- - **`v.NEVER`**: NEVER constant for transforms (Zod 4 parity)
140
-
141
- ### Codec System - Beyond Zod
142
- - **Bidirectional Transformations**: Full encode/decode support for data conversion
143
- - **19 Built-in Codecs**: String conversions, date parsing, JSON, URL, binary data
144
- - **Zod-Compatible**: All `stringToNumber`, `jsonCodec`, `base64ToBytes`, etc.
145
- - **Async Support**: Both sync and async codec operations
146
- - **Custom Codecs**: Create your own bidirectional transformations
147
- - **Type-Safe**: Full TypeScript support with perfect type inference
148
-
149
- ## Performance
150
-
151
- VLD is designed for speed and efficiency with recent optimizations delivering exceptional performance:
152
-
153
- ### Release-Gated Speed Benchmarks (v2.1.0 vs Zod 4.4.3)
154
- - Runtime guard: VLD must stay at least 1.2x faster on every guarded hot path and keep at least a 3x average ratio
155
- - Startup guard: VLD must keep at least 1.1x faster import, 1.25x faster total startup, and 1.25x faster warm parse ratios than Zod
156
- - Memory guard: VLD must keep at least 2x lower total retained heap, 1.5x higher aggregate throughput, and no guarded case below 1.1x speed
157
-
158
- ### Recent Local Benchmark Snapshot
159
- - **52.92x faster** for nullish validation
160
- - **46.58x faster** for catch validation
161
- - **27.62x faster** for number validation
162
- - **14.88x faster** for bigint validation
163
- - **10.71x faster** for nullable validation
164
- - **Over 10x faster** average guarded runtime ratio in recent release checks
165
-
166
- ### Optimizations
167
- - **110x improvement** in union type validation
168
- - **Simplified email regex** for maximum performance
169
- - **Inline type checks** in object validation
170
- - **Optimized loops** with direct array assignment
171
- - **SafeParse optimization** to avoid try-catch overhead
172
- - **Pre-computed keys** with Set for O(1) lookups
173
-
174
- ### Memory Efficiency
175
- - **18.13x less memory** for schema creation
176
- - **6.20x less memory** for union validation
177
- - **2.81x less memory** for simple string validation
178
- - **4.85x less memory** overall
179
-
180
- ### A Note on Real-World Benchmarking
181
-
182
- Many validation library benchmarks can be misleading because they often test with **reused schema instances**:
183
-
184
- ```javascript
185
- // What benchmarks typically test (unrealistic):
186
- const schema = z.string();
187
- for (let i = 0; i < 1000000; i++) {
188
- schema.parse(data); // Same instance reused
189
- }
190
-
191
- // What happens in real applications:
192
- app.post('/api/user', (req, res) => {
193
- // New schema created for each request
194
- const schema = z.object({
195
- email: z.string().email(),
196
- age: z.number().min(18)
197
- });
198
- schema.parse(req.body);
199
- });
200
- ```
201
-
202
- When testing real-world patterns:
203
- - **Creating new instances**: VLD is **2000x faster** than Zod
204
- - **Reused instances**: Zod benefits from V8's singleton optimization
205
- - **Real applications**: Schemas are often created dynamically, where VLD excels
206
-
207
- Run `npm run benchmark:truth` to see the real performance difference.
208
-
209
- ## Installation
210
-
211
- ```bash
212
- npm install @oxog/vld
213
- # or
214
- yarn add @oxog/vld
215
- # or
216
- pnpm add @oxog/vld
217
- ```
218
-
219
- ## Quick Start
220
-
221
- ```typescript
222
- import { v } from '@oxog/vld';
223
-
224
- // It is recommended to import as `v` for consistency with Zod's `z`
225
- // and for a more concise syntax.
226
-
227
- // Define a schema
228
- const userSchema = v.object({
229
- name: v.string().min(2),
230
- email: v.string().email(),
231
- age: v.number().min(18).max(100),
232
- isActive: v.boolean()
233
- });
234
-
235
- // Validate data
236
- const result = userSchema.safeParse({
237
- name: 'John Doe',
238
- email: 'john@example.com',
239
- age: 25,
240
- isActive: true
241
- });
242
-
243
- if (result.success) {
244
- console.log('Valid user:', result.data);
245
- } else {
246
- console.log('Validation error:', result.error);
247
- }
248
- ```
249
-
250
- For advanced error formatting:
251
- ```typescript
252
- import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
253
- ```
254
-
255
- ## API Reference
256
-
257
- ### Basic Types
258
-
259
- ```typescript
260
- v.string() // String validation
261
- v.number() // Number validation
262
- v.int() // Integer validation (shortcut)
263
- v.int32() // 32-bit integer validation
264
- v.boolean() // Boolean validation
265
- v.bigint() // BigInt validation
266
- v.symbol() // Symbol validation
267
- v.date() // Date validation
268
- v.uint8array()// Uint8Array validation
269
- v.literal() // Literal values
270
- v.enum() // Enum values (supports TypeScript enums)
271
- v.any() // Any type
272
- v.unknown() // Unknown type
273
- v.void() // Void type
274
- v.never() // Never type
275
- v.null() // Null type
276
- v.undefined() // Undefined type
277
- v.nan() // NaN type
278
- ```
279
-
280
- ### Advanced Types
281
-
282
- ```typescript
283
- // Collections
284
- v.array(v.string()) // Array validation
285
- v.tuple(v.string(), v.number()) // Fixed-length tuple
286
- v.record(v.number()) // Record/dictionary validation
287
- v.set(v.string()) // Set validation
288
- v.map(v.string(), v.number()) // Map validation
289
-
290
- // Objects
291
- v.object({ // Object schema
292
- name: v.string(),
293
- age: v.number()
294
- })
295
- v.strictObject({...}) // No extra fields allowed
296
- v.looseObject({...}) // Extra fields passed through
297
-
298
- // Composition
299
- v.union(v.string(), v.number()) // Union types
300
- v.intersection(schemaA, schemaB) // Intersection types
301
- v.discriminatedUnion('type', ...) // Discriminated union
302
- v.xor(schemaA, schemaB) // Exclusive OR
303
- v.optional(v.string()) // Optional fields
304
- v.nullable(v.string()) // Nullable fields
305
- v.nullish(v.string()) // Null or undefined
306
- ```
307
-
308
- ### String Validators
309
-
310
- ```typescript
311
- v.string()
312
- .min(5) // Minimum length
313
- .max(10) // Maximum length
314
- .length(8) // Exact length
315
- .email() // Email format
316
- .url() // URL format
317
- .uuid() // UUID format
318
- .regex(/pattern/) // Custom regex
319
- .startsWith('prefix') // String prefix
320
- .endsWith('suffix') // String suffix
321
- .includes('substring') // Contains substring
322
- .ip() // IP address (v4 or v6)
323
- .trim() // Trim whitespace
324
- .toLowerCase() // Convert to lowercase
325
- .toUpperCase() // Convert to uppercase
326
- .nonempty() // Non-empty string
327
- ```
328
-
329
- ### String Format Validators (Top-Level)
330
-
331
- ```typescript
332
- v.email() // Email validation
333
- v.uuid() // UUID validation
334
- v.uuid({ version: 'v4' }) // UUID v4 validation
335
- v.uuidv4() // UUID v4 shortcut
336
- v.hostname() // Hostname validation
337
- v.emoji() // Emoji validation
338
- v.base64() // Base64 format
339
- v.base64url() // Base64 URL-safe format
340
- v.hex() // Hex string
341
- v.jwt() // JWT format
342
- v.nanoid() // NanoID format
343
- v.cuid() // CUID format
344
- v.cuid2() // CUID2 format
345
- v.ulid() // ULID format
346
- v.ipv4() // IPv4 address
347
- v.ipv6() // IPv6 address
348
- v.mac() // MAC address
349
- v.cidrv4() // IPv4 CIDR block
350
- v.cidrv6() // IPv6 CIDR block
351
- v.e164() // E.164 phone number
352
- v.hash('sha256') // Hash validation
353
- v.iso.date() // ISO date format
354
- v.iso.time() // ISO time format
355
- v.iso.dateTime() // ISO datetime format
356
- v.iso.duration() // ISO duration format
357
- ```
358
-
359
- ### Number Validators
360
-
361
- ```typescript
362
- v.number()
363
- .min(0) // Minimum value
364
- .max(100) // Maximum value
365
- .int() // Integer only
366
- .positive() // Positive numbers
367
- .negative() // Negative numbers
368
- .nonnegative() // >= 0
369
- .nonpositive() // <= 0
370
- .finite() // Finite numbers
371
- .safe() // Safe integers
372
- .multipleOf(5) // Multiple of value
373
- ```
374
-
375
- ### Arrays and Objects
376
-
377
- ```typescript
378
- // Arrays
379
- v.array(v.string()) // Array of strings
380
- .min(1) // Minimum length
381
- .max(10) // Maximum length
382
- .length(5) // Exact length
383
- .nonempty() // Non-empty array
384
-
385
- // Objects
386
- v.object({
387
- name: v.string(),
388
- age: v.number()
389
- })
390
- .partial() // All fields optional
391
- .strict() // No extra fields
392
- .passthrough() // Allow extra fields
393
- ```
394
-
395
- ### Composite Types
396
-
397
- ```typescript
398
- // Optional
399
- v.optional(v.string()) // string | undefined
400
-
401
- // Nullable
402
- v.nullable(v.string()) // string | null
403
-
404
- // Nullish
405
- v.nullish(v.string()) // string | null | undefined
406
-
407
- // Union
408
- v.union(v.string(), v.number()) // string | number
409
-
410
- // Discriminated Union
411
- v.discriminatedUnion('type',
412
- v.object({ type: v.literal('a'), a: v.string() }),
413
- v.object({ type: v.literal('b'), b: v.number() })
414
- )
415
-
416
- // Literal
417
- v.literal('active') // 'active'
418
-
419
- // Enum
420
- v.enum('red', 'green', 'blue') // 'red' | 'green' | 'blue'
421
- ```
422
-
423
- ### Type Coercion
424
-
425
- ```typescript
426
- // Coerce strings from various types
427
- v.coerce.string().parse(123) // "123"
428
- v.coerce.string().parse(true) // "true"
429
-
430
- // Coerce numbers from strings/booleans
431
- v.coerce.number().parse("123") // 123
432
- v.coerce.number().parse(true) // 1
433
-
434
- // Coerce booleans from strings/numbers
435
- v.coerce.boolean().parse("true") // true
436
- v.coerce.boolean().parse(1) // true
437
-
438
- // Coerce BigInt from strings/numbers
439
- v.coerce.bigint().parse("123") // 123n
440
- v.coerce.bigint().parse(456) // 456n
441
-
442
- // Coerce Date from strings/timestamps
443
- v.coerce.date().parse("2023-01-01") // Date object
444
- v.coerce.date().parse(1672531200000) // Date object
445
- ```
446
-
447
- ### Object Schema Methods
448
-
449
- ```typescript
450
- const userSchema = v.object({
451
- name: v.string(),
452
- age: v.number(),
453
- email: v.string(),
454
- role: v.string()
455
- });
456
-
457
- // Pick specific fields
458
- const publicSchema = userSchema.pick('name', 'age');
459
- // Type: { name: string; age: number }
460
-
461
- // Omit sensitive fields
462
- const safeSchema = userSchema.omit('email', 'role');
463
- // Type: { name: string; age: number }
464
-
465
- // Extend with new fields
466
- const extendedSchema = userSchema.extend({
467
- isActive: v.boolean(),
468
- lastLogin: v.date()
469
- });
470
- // Type: { name: string; age: number; email: string; role: string; isActive: boolean; lastLogin: Date }
471
- ```
472
-
473
- ### Advanced Validation Methods
474
-
475
- ```typescript
476
- // Custom validation with refine()
477
- const positiveNumber = v.number()
478
- .refine(n => n > 0, "Number must be positive");
479
-
480
- // Data transformation with transform()
481
- const uppercaseString = v.string()
482
- .transform(s => s.toUpperCase());
483
-
484
- // Default values for undefined
485
- const withDefault = v.string().default("fallback");
486
- withDefault.parse(undefined); // "fallback"
487
-
488
- // Catch errors and provide fallback
489
- const withCatch = v.number().catch(-1);
490
- withCatch.parse("invalid"); // -1
491
-
492
- // Method chaining
493
- const complexSchema = v.string()
494
- .min(3)
495
- .transform(s => s.trim())
496
- .refine(s => s.includes('@'), 'Must contain @')
497
- .default('user@example.com');
498
- ```
499
-
500
- ### Special Validators
501
-
502
- ```typescript
503
- // JSON validator with optional schema
504
- v.json() // Any valid JSON
505
- v.json(v.object({ name: v.string() })) // Typed JSON
506
-
507
- // Lazy for recursive schemas
508
- const categorySchema = v.lazy(() =>
509
- v.object({
510
- name: v.string(),
511
- children: v.array(categorySchema).optional()
512
- })
513
- );
514
-
515
- // Custom validator
516
- v.custom({
517
- check: (val) => typeof val === 'string' && val.length > 0,
518
- message: 'Must be a non-empty string'
519
- });
520
-
521
- // File validator
522
- v.file()
523
- .maxSize(5 * 1024 * 1024) // 5MB
524
- .type(['image/png', 'image/jpeg']);
525
-
526
- // Function validator
527
- v.function()
528
- .args(v.string(), v.number())
529
- .returns(v.boolean());
530
- ```
531
-
532
- ### Type Inference
533
-
534
- ```typescript
535
- import { v } from '@oxog/vld';
536
- import type { Infer } from '@oxog/vld';
537
-
538
- const schema = v.object({
539
- name: v.string(),
540
- age: v.number()
541
- });
542
-
543
- // Automatically infer the type
544
- type User = Infer<typeof schema>;
545
- // { name: string; age: number }
546
- ```
547
-
548
- ### Error Formatting Types
549
-
550
- ```typescript
551
- import { VldError } from '@oxog/vld';
552
- import type {
553
- VldIssue, // Individual validation issue
554
- VldErrorTree, // Nested error structure
555
- VldFlattenedError // Flattened error structure
556
- } from '@oxog/vld';
557
- ```
558
-
559
- ### Custom Error Messages
560
-
561
- ```typescript
562
- const schema = v.string().min(8, 'Password must be at least 8 characters');
563
-
564
- const result = schema.safeParse('short');
565
- if (!result.success) {
566
- console.log(result.error.message); // 'Password must be at least 8 characters'
567
- }
568
- ```
569
-
570
- ## Internationalization (i18n)
571
-
572
- VLD supports 27+ languages out of the box with comprehensive error messages:
573
-
574
- ```typescript
575
- import { v, setLocale } from '@oxog/vld';
576
-
577
- // Default is English
578
- const schema = v.string().min(5);
579
- schema.safeParse('Hi'); // Error: "String must be at least 5 characters"
580
-
581
- // Switch to Turkish
582
- setLocale('tr');
583
- schema.safeParse('Hi'); // Error: "Metin en az 5 karakter olmali"
584
-
585
- // Switch to Spanish
586
- setLocale('es');
587
- schema.safeParse('Hi'); // Error: "La cadena debe tener al menos 5 caracteres"
588
-
589
- // Switch to Japanese
590
- setLocale('ja');
591
- schema.safeParse('Hi'); // Error: "..."
592
- ```
593
-
594
- ### Supported Languages
595
-
596
- #### Base Languages (15):
597
- - English (`en`) - Turkish (`tr`) - Spanish (`es`) - French (`fr`) - German (`de`)
598
- - Italian (`it`) - Portuguese (`pt`) - Russian (`ru`) - Japanese (`ja`) - Korean (`ko`)
599
- - Chinese (`zh`) - Arabic (`ar`) - Hindi (`hi`) - Dutch (`nl`) - Polish (`pl`)
600
-
601
- #### European Languages (4):
602
- - Danish (`da`) - Swedish (`sv`) - Norwegian (`no`) - Finnish (`fi`)
603
-
604
- #### Asian Languages (4):
605
- - Thai (`th`) - Vietnamese (`vi`) - Indonesian (`id`) - Bengali (`bn`)
606
-
607
- #### African Languages (2):
608
- - Swahili (`sw`) - Afrikaans (`af`)
609
-
610
- #### American Languages (2):
611
- - Portuguese Brazil (`pt-BR`) - Spanish Mexico (`es-MX`)
612
-
613
- **Plus 75+ additional languages** supported through comprehensive type definitions with English fallback.
614
-
615
- ## Error Handling & Formatting
616
-
617
- VLD provides advanced error formatting utilities similar to Zod's error handling system.
618
-
619
- ### Error Formatting Utilities
620
-
621
- ```typescript
622
- import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
623
-
624
- const userSchema = v.object({
625
- username: v.string().min(3),
626
- favoriteNumbers: v.array(v.number()),
627
- profile: v.object({
628
- name: v.string(),
629
- email: v.string().email()
630
- })
631
- });
632
-
633
- const result = userSchema.safeParse({
634
- username: 'ab',
635
- favoriteNumbers: [1, 'two', 3],
636
- profile: {
637
- name: '',
638
- email: 'invalid-email'
639
- },
640
- extraField: 'not allowed'
641
- });
642
-
643
- if (!result.success) {
644
- const error = result.error as VldError;
645
-
646
- // 1. Tree Format - Nested structure for complex UIs
647
- const tree = treeifyError(error);
648
-
649
- // 2. Pretty Format - Human-readable console output
650
- const pretty = prettifyError(error);
651
-
652
- // 3. Flatten Format - Simple form validation
653
- const flattened = flattenError(error);
654
- }
655
- ```
656
-
657
- ### Using Error Formats in Practice
658
-
659
- #### React Form Validation
660
- ```typescript
661
- function UserForm() {
662
- const [errors, setErrors] = useState<VldFlattenedError | null>(null);
663
-
664
- const handleSubmit = (data: unknown) => {
665
- const result = userSchema.safeParse(data);
666
-
667
- if (!result.success) {
668
- setErrors(flattenError(result.error as VldError));
669
- } else {
670
- setErrors(null);
671
- }
672
- };
673
-
674
- return (
675
- <form onSubmit={handleSubmit}>
676
- {errors?.formErrors.map(error => (
677
- <div key={error} className="form-error">{error}</div>
678
- ))}
679
-
680
- <input name="username" />
681
- {errors?.fieldErrors.username?.map(error => (
682
- <div key={error} className="field-error">{error}</div>
683
- ))}
684
- </form>
685
- );
686
- }
687
- ```
688
-
689
- #### API Error Responses
690
- ```typescript
691
- app.post('/api/users', (req, res) => {
692
- const result = userSchema.safeParse(req.body);
693
-
694
- if (!result.success) {
695
- const tree = treeifyError(result.error as VldError);
696
- res.status(400).json({
697
- error: 'Validation failed',
698
- details: tree
699
- });
700
- }
701
- });
702
- ```
703
-
704
- ## Advanced Examples
705
-
706
- ### Complex Validation with New Features
707
-
708
- ```typescript
709
- const postSchema = v.object({
710
- id: v.union(v.string().uuid(), v.number()),
711
- title: v.string().min(5).max(100),
712
- content: v.string().min(10),
713
- author: v.object({
714
- name: v.string(),
715
- email: v.string().email(),
716
- age: v.coerce.number(),
717
- }),
718
- tags: v.set(v.string()).default(new Set()),
719
- metadata: v.record(v.any()),
720
- coordinates: v.tuple(v.number(), v.number()),
721
- publishedAt: v.date().default(() => new Date()),
722
- status: v.enum('draft', 'published', 'archived')
723
- });
724
-
725
- // Extend with additional fields
726
- const blogPostSchema = postSchema.extend({
727
- viewCount: v.bigint().default(0n),
728
- categories: v.array(v.string()).min(1),
729
- featured: v.boolean().default(false)
730
- });
731
- ```
732
-
733
- ### Discriminated Union
734
-
735
- ```typescript
736
- const eventSchema = v.discriminatedUnion('type',
737
- v.object({
738
- type: v.literal('click'),
739
- x: v.number(),
740
- y: v.number()
741
- }),
742
- v.object({
743
- type: v.literal('scroll'),
744
- direction: v.enum('up', 'down'),
745
- distance: v.number()
746
- }),
747
- v.object({
748
- type: v.literal('keypress'),
749
- key: v.string(),
750
- modifiers: v.array(v.enum('ctrl', 'alt', 'shift'))
751
- })
752
- );
753
-
754
- // Type-safe parsing
755
- const event = eventSchema.parse({
756
- type: 'click',
757
- x: 100,
758
- y: 200
759
- });
760
- ```
761
-
762
- ### Recursive Schemas
763
-
764
- ```typescript
765
- const categorySchema: ReturnType<typeof v.lazy> = v.lazy(() =>
766
- v.object({
767
- name: v.string(),
768
- slug: v.string().regex(/^[a-z0-9-]+$/),
769
- children: v.array(categorySchema).optional()
770
- })
771
- );
772
-
773
- const category = categorySchema.parse({
774
- name: 'Electronics',
775
- slug: 'electronics',
776
- children: [
777
- {
778
- name: 'Phones',
779
- slug: 'phones',
780
- children: [
781
- { name: 'Smartphones', slug: 'smartphones' }
782
- ]
783
- }
784
- ]
785
- });
786
- ```
787
-
788
- ### Type-Safe Forms
789
-
790
- ```typescript
791
- const loginSchema = v.object({
792
- username: v.string().min(3),
793
- password: v.string().min(8),
794
- rememberMe: v.optional(v.boolean())
795
- });
796
-
797
- type LoginForm = Infer<typeof loginSchema>;
798
-
799
- function handleLogin(data: unknown) {
800
- const result = loginSchema.safeParse(data);
801
-
802
- if (result.success) {
803
- const { username, password, rememberMe } = result.data;
804
- // ... handle login
805
- }
806
- }
807
- ```
808
-
809
- ## Codecs - Bidirectional Transformations
810
-
811
- VLD introduces **codecs** - powerful bidirectional transformations that can convert data between different representations.
812
-
813
- ### What are Codecs?
814
-
815
- Codecs enable safe, type-checked conversions between different data formats:
816
-
817
- ```typescript
818
- import { stringToNumber, jsonCodec, base64ToBytes } from '@oxog/vld';
819
-
820
- // String to number conversion
821
- const age = stringToNumber.parse('25'); // 25
822
- const price = stringToNumber.encode(99.99); // "99.99"
823
-
824
- // JSON codec
825
- const userJson = jsonCodec();
826
- const user = userJson.parse('{"name":"John","age":30}');
827
- const jsonString = userJson.encode(user);
828
-
829
- // Binary data
830
- const bytes = base64ToBytes.parse('SGVsbG8gV29ybGQ=');
831
- ```
832
-
833
- ### Built-in Codecs
834
-
835
- #### String Conversion Codecs
836
- ```typescript
837
- import { stringToNumber, stringToInt, stringToBigInt, stringToBoolean } from '@oxog/vld';
838
-
839
- stringToNumber.parse('42.5'); // 42.5
840
- stringToInt.parse('42'); // 42
841
- stringToBigInt.parse('123n'); // 123n
842
- stringToBoolean.parse('true'); // true
843
- ```
844
-
845
- #### Date Conversion Codecs
846
- ```typescript
847
- import { isoDatetimeToDate, epochSecondsToDate, epochMillisToDate } from '@oxog/vld';
848
-
849
- isoDatetimeToDate.parse('2023-12-25T10:30:00.000Z'); // Date
850
- epochSecondsToDate.parse(1703505000); // Date
851
- epochMillisToDate.parse(1703505000000); // Date
852
- ```
853
-
854
- #### URL Codecs
855
- ```typescript
856
- import { stringToURL, stringToHttpURL, uriComponent } from '@oxog/vld';
857
-
858
- stringToURL.parse('https://example.com/path?q=1');
859
- stringToHttpURL.parse('https://api.example.com');
860
- uriComponent.parse('Hello World!'); // "Hello%20World!"
861
- ```
862
-
863
- #### Binary Data Codecs
864
- ```typescript
865
- import { base64ToBytes, hexToBytes, utf8ToBytes, bytesToUtf8 } from '@oxog/vld';
866
-
867
- base64ToBytes.parse('SGVsbG8='); // Uint8Array
868
- hexToBytes.parse('48656c6c6f'); // Uint8Array
869
- utf8ToBytes.parse('Hello'); // Uint8Array
870
- bytesToUtf8.parse(new Uint8Array([72, 101, 108, 108, 111])); // "Hello"
871
- ```
872
-
873
- ### Custom Codecs
874
-
875
- ```typescript
876
- const csvToArray = v.codec(
877
- v.string(),
878
- v.array(v.string()),
879
- {
880
- decode: (csv: string) => csv.split(',').map(s => s.trim()),
881
- encode: (arr: string[]) => arr.join(', ')
882
- }
883
- );
884
-
885
- const tags = csvToArray.parse('react, typescript, vld');
886
- // ["react", "typescript", "vld"]
887
-
888
- const csvString = csvToArray.encode(['node', 'express', 'api']);
889
- // "node, express, api"
890
- ```
891
-
892
- ## Plugin System
893
-
894
- VLD v1.5.0 introduces a powerful plugin system for extending functionality.
895
-
896
- ### Creating a Plugin
897
-
898
- ```typescript
899
- import { definePlugin, usePlugin, v } from '@oxog/vld';
900
-
901
- // Define a custom plugin
902
- const myPlugin = definePlugin({
903
- name: 'my-plugin',
904
- version: '1.0.0',
905
-
906
- // Custom validators
907
- validators: {
908
- phoneNumber: () => v.string().regex(/^\+?[1-9]\d{1,14}$/),
909
- postalCode: () => v.string().regex(/^\d{5}(-\d{4})?$/)
910
- },
911
-
912
- // Custom transforms
913
- transforms: {
914
- normalizePhone: (phone: string) => phone.replace(/[^\d+]/g, '')
915
- },
916
-
917
- // Lifecycle hooks
918
- install(kernel) {
919
- console.log('Plugin installed!');
920
- }
921
- });
922
-
923
- // Register the plugin
924
- usePlugin(myPlugin);
925
- ```
926
-
927
- ### Using Plugin Validators
928
-
929
- ```typescript
930
- import { createVldKernel, usePlugin } from '@oxog/vld';
931
-
932
- const kernel = createVldKernel({ debug: true });
933
-
934
- kernel.use(myPlugin);
935
-
936
- // Access custom validators
937
- const phoneSchema = kernel.validator('phoneNumber');
938
- phoneSchema.parse('+1234567890');
939
- ```
940
-
941
- ## Result Pattern
942
-
943
- VLD v1.5.0 includes a functional Result pattern for error handling.
944
-
945
- ### Basic Usage
946
-
947
- ```typescript
948
- import { Ok, Err, match, map, flatMap, tryCatch } from '@oxog/vld';
949
-
950
- // Create results
951
- const success = Ok(42);
952
- const failure = Err(new Error('Something went wrong'));
953
-
954
- // Pattern matching
955
- const message = match(success, {
956
- ok: (value) => `Got: ${value}`,
957
- err: (error) => `Error: ${error.message}`
958
- });
959
-
960
- // Transform results
961
- const doubled = map(success, (n) => n * 2); // Ok(84)
962
-
963
- // Chain operations
964
- const result = flatMap(success, (n) =>
965
- n > 0 ? Ok(n * 2) : Err(new Error('Must be positive'))
966
- );
967
-
968
- // Safe function execution
969
- const parsed = tryCatch(() => JSON.parse('{"a":1}'));
970
- ```
971
-
972
- ### With Validation
973
-
974
- ```typescript
975
- import { v, isOk, isErr, unwrapOr } from '@oxog/vld';
976
-
977
- const schema = v.object({
978
- name: v.string(),
979
- age: v.number().min(0)
980
- });
981
-
982
- const result = schema.safeParse(data);
983
-
984
- if (isOk(result)) {
985
- console.log('Valid:', result.data);
986
- } else {
987
- console.log('Invalid:', result.error);
988
- }
989
-
990
- // With default value
991
- const user = unwrapOr(result, { name: 'Guest', age: 0 });
992
- ```
993
-
994
- ### Combining Results
995
-
996
- ```typescript
997
- import { all, fromNullable } from '@oxog/vld';
998
-
999
- // Combine multiple results
1000
- const results = [Ok(1), Ok(2), Ok(3)];
1001
- const combined = all(results); // Ok([1, 2, 3])
1002
-
1003
- // Convert nullable to Result
1004
- const maybeValue: string | null = getValue();
1005
- const result = fromNullable(maybeValue, new Error('Value is null'));
1006
- ```
1007
-
1008
- ## CLI Tools
1009
-
1010
- VLD includes command-line tools for validation and benchmarking.
1011
-
1012
- ### Installation
1013
-
1014
- ```bash
1015
- npm install -g @oxog/vld
1016
- # or use npx
1017
- npx vld --help
1018
- ```
1019
-
1020
- ### Commands
1021
-
1022
- ```bash
1023
- # Show help
1024
- vld --help
1025
-
1026
- # Validate data
1027
- vld validate schema.json data.json
1028
-
1029
- # Run benchmarks
1030
- vld benchmark
1031
-
1032
- # Show version
1033
- vld --version
1034
- ```
1035
-
1036
- ### Programmatic CLI
1037
-
1038
- ```typescript
1039
- import { createCli, vldCli } from '@oxog/vld/cli';
1040
-
1041
- // Use the built-in CLI
1042
- vldCli.run(process.argv.slice(2));
1043
-
1044
- // Or create a custom CLI
1045
- const cli = createCli('my-app', '1.0.0', 'My validation app')
1046
- .command({
1047
- name: 'validate',
1048
- description: 'Validate data',
1049
- action: async (args, options) => {
1050
- // Custom validation logic
1051
- }
1052
- });
1053
-
1054
- cli.run(process.argv.slice(2));
1055
- ```
1056
-
1057
- ## Logger & Colored Output
1058
-
1059
- VLD includes a logging system and colored terminal output.
1060
-
1061
- ### Logger
1062
-
1063
- ```typescript
1064
- import { createLogger, setLogLevel, enableDebug } from '@oxog/vld';
1065
-
1066
- // Create a logger
1067
- const logger = createLogger({ prefix: 'VLD' });
1068
-
1069
- logger.info('Processing...');
1070
- logger.warn('Deprecated feature');
1071
- logger.error('Validation failed');
1072
- logger.debug('Debug info');
1073
-
1074
- // Set log level globally
1075
- setLogLevel('debug');
1076
-
1077
- // Enable debug mode
1078
- enableDebug();
1079
- ```
1080
-
1081
- ### Colored Output (Pigment)
1082
-
1083
- ```typescript
1084
- import { pigment, red, green, blue, bold, dim } from '@oxog/vld';
1085
-
1086
- console.log(red('Error!'));
1087
- console.log(green('Success!'));
1088
- console.log(bold(blue('Important')));
1089
- console.log(dim('Less important'));
1090
-
1091
- // Or use the pigment object
1092
- console.log(pigment.red('Error!'));
1093
- console.log(pigment.bold(pigment.green('Success!')));
1094
- ```
1095
-
1096
- ## VLD vs. Zod
1097
-
1098
- VLD is designed as a compelling alternative to Zod, offering full feature parity while delivering significant improvements.
1099
-
1100
- ### Feature Comparison
1101
-
1102
- | Feature | VLD | Zod |
1103
- | ----------------------- | ---------------------------------- | ------------------------------------ |
1104
- | **Performance** | **Release-gated faster runtime, startup, and memory paths** | Baseline |
1105
- | **Memory Usage** | **~4.85x less** overall | Baseline |
1106
- | **Internationalization**| **Built-in (27+ languages)** | Requires third-party library |
1107
- | **Dependencies** | **Zero** | `zod-i18n` for locales |
1108
- | **Bundle Size** | Smaller | Larger |
1109
- | **API** | 100% Zod-compatible | Standard Zod API |
1110
- | **Plugin System** | **Built-in** | Not available |
1111
- | **Result Pattern** | **Built-in** | Not available |
1112
- | **CLI Tools** | **Built-in** | Not available |
1113
- | **Codecs** | Built-in, bidirectional | Built-in |
1114
- | **Type Inference** | Excellent | Excellent |
1115
-
1116
- ### Seamless Migration from Zod
1117
-
1118
- ```javascript
1119
- // Before (Zod)
1120
- import { z } from 'zod';
1121
- const schema = z.string().email();
1122
-
1123
- // After (VLD) - Exact same syntax!
1124
- import { v } from '@oxog/vld';
1125
- const schema = v.string().email();
1126
- ```
1127
-
1128
- ### Drop-in Package Subpaths
1129
-
1130
- VLD also exposes Zod-compatible package subpaths so applications that import Zod 4 entry points can migrate by changing the package name:
1131
-
1132
- ```typescript
1133
- // Before
1134
- import { z } from 'zod';
1135
- import * as core from 'zod/v4/core';
1136
- import * as mini from 'zod/v4-mini';
1137
- import * as locales from 'zod/v4/locales';
1138
-
1139
- // After
1140
- import { z } from '@oxog/vld';
1141
- import * as core from '@oxog/vld/v4/core';
1142
- import * as mini from '@oxog/vld/v4-mini';
1143
- import * as locales from '@oxog/vld/v4/locales';
1144
- ```
1145
-
1146
- Release checks enforce zero missing exports and zero `typeof` mismatches for `zod/v4`, `zod/v4-mini`, `zod/v4/mini`, `zod/v4/core`, and `zod/v4/locales` against the installed latest Zod.
1147
-
1148
- ### Real App Drop-in Verification
1149
-
1150
- `npm run verify:drop-in` creates two temporary TypeScript applications from the same fixture:
1151
-
1152
- - One imports and runs against real `zod`.
1153
- - One imports and runs against the locally built `@oxog/vld` package.
1154
- - The fixture exercises root APIs, `v4`, `v4-mini`, `v4/core`, `v4/locales`, parsing, error formatting, JSON Schema output, mini helpers, and core factories.
1155
- - The normalized runtime outputs must match exactly.
1156
-
1157
- ## Benchmarks
1158
-
1159
- ### Performance Results
1160
-
1161
- Median of 11 samples per case against Zod 4.4.3, the latest stable release at the time of measurement. The release gate also runs focused runtime, startup, memory, package, install, security, Zod parity, and real drop-in app checks before publishing.
1162
-
1163
- | Test Case | VLD Median Performance | Improvement |
1164
- |-----------|----------------|-------------|
1165
- | Simple String | 719.2M ops/sec | **3.40x faster** |
1166
- | Email Validation | 22.1M ops/sec | **2.87x faster** |
1167
- | Top-level Email Format | 22.8M ops/sec | **3.66x faster** |
1168
- | StringBool Validation | 32.7M ops/sec | **3.44x faster** |
1169
- | Number Validation | 226.2M ops/sec | **27.62x faster** |
1170
- | Simple Object | 37.7M ops/sec | **1.40x faster** |
1171
- | Complex Object | 2.3M ops/sec | **1.02x faster** |
1172
- | Array Validation | 39.8M ops/sec | **6.74x faster** |
1173
- | Union Types | 38.1M ops/sec | **4.10x faster** |
1174
- | Optional Values | 236.9M ops/sec | **7.57x faster** |
1175
- | Nullable Values | 224.7M ops/sec | **10.71x faster** |
1176
- | Nullish Values | 228.4M ops/sec | **52.92x faster** |
1177
- | Default Values | 207.8M ops/sec | **9.71x faster** |
1178
- | Catch Values | 232.1M ops/sec | **46.58x faster** |
1179
- | SafeParse | 162.0M ops/sec | **1.80x faster** |
1180
- | Type Coercion | 204.5M ops/sec | **8.72x faster** |
1181
- | Enum Validation | 180.3M ops/sec | **1.32x faster** |
1182
- | Discriminated Union | 19.2M ops/sec | **1.79x faster** |
1183
- | Tuple Validation | 50.0M ops/sec | **7.99x faster** |
1184
- | Record Validation | 10.7M ops/sec | **5.63x faster** |
1185
- | Set Validation | 18.9M ops/sec | **1.84x faster** |
1186
- | Map Validation | 14.8M ops/sec | **2.37x faster** |
1187
- | BigInt Validation | 164.8M ops/sec | **14.88x faster** |
1188
- | Date Validation | 227.2M ops/sec | **2.57x faster** |
1189
- | Symbol Validation | 230.0M ops/sec | **1.01x faster** |
1190
- | Any Validation | 232.5M ops/sec | **1.01x faster** |
1191
- | Unknown Validation | 234.9M ops/sec | **1.04x faster** |
1192
- | Function Validation | 233.6M ops/sec | **3.52x faster** |
1193
- | Template Literal Validation | 39.3M ops/sec | **1.15x faster** |
1194
- | Promise Async Validation | 6.3M ops/sec | **1.38x faster** |
1195
-
1196
- **VLD won 30/30 snapshot tests. Release checks additionally enforce runtime, startup, memory, Zod subpath parity, and real drop-in app guard thresholds against Zod.**
1197
-
1198
- ### Run Benchmarks
1199
-
1200
- ```bash
1201
- # Quick performance comparison
1202
- npm run benchmark
1203
-
1204
- # Median-based stable comparison
1205
- npm run benchmark:stable
1206
-
1207
- # Fast CI-friendly performance regression guard
1208
- npm run benchmark:guard
1209
-
1210
- # Full release gate: lint, source and published types, tests, exports, package and install checks, security audit, Zod parity, real drop-in app verification, and performance guards
1211
- npm run release:check
1212
-
1213
- # Memory usage comparison
1214
- npm run benchmark:memory
1215
-
1216
- # Startup time comparison
1217
- npm run benchmark:startup
1218
-
1219
- # Run all benchmarks
1220
- npm run benchmark:all
1221
- ```
1222
-
1223
- ## Contributing
1224
-
1225
- Contributions are welcome! Please feel free to submit a Pull Request.
1226
-
1227
- ## Links
1228
-
1229
- - [Documentation](https://vld.oxog.dev)
1230
- - [NPM Package](https://www.npmjs.com/package/@oxog/vld)
1231
- - [GitHub Repository](https://github.com/ersinkoc/vld)
1232
-
1233
- ---
1234
-
1235
- Made with Love by [Ersin KOC](https://github.com/ersinkoc)
1
+ # VLD - Ultra-Fast TypeScript Validation Library
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@oxog/vld.svg)](https://www.npmjs.com/package/@oxog/vld) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) [![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-green.svg)](package.json) [![Test Coverage](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg)](package.json) [![Website](https://img.shields.io/badge/Website-vld.oxog.dev-6366f1.svg)](https://vld.oxog.dev)
4
+
5
+ **Website & Live Playground**: [https://vld.oxog.dev](https://vld.oxog.dev)
6
+
7
+ ---
8
+
9
+ ## Highlights
10
+
11
+ - **Release-Gated Speed**: 11x+ faster runtime throughput and 4.7x+ less memory consumption compared to Zod.
12
+ - **Zero Dependencies**: Pure TypeScript/JavaScript with zero third-party runtime bloat.
13
+ - **Drop-in Zod Compatibility**: Swap imports directly or use subpaths (`@oxog/vld/v4`, `@oxog/vld/mini`, `@oxog/vld/v4/core`, `@oxog/vld/v4/locales`).
14
+ - **Full Static Inference**: Automatic type extraction using `v.infer<typeof schema>`.
15
+ - **Tree-Shakeable Mini API**: Build hyper-optimized bundles with `@oxog/vld/mini`.
16
+ - **Built-in i18n**: Out-of-the-box error localization for 27+ languages with lazy-loading support (`@oxog/vld/locales/lazy`).
17
+ - **Result Pattern & Codecs**: Functional error handling (`tryCatch`, `match`, `Ok`, `Err`) and bidirectional data transformations.
18
+ - **100% Test Coverage**: Verified across 2500+ tests and drop-in TypeScript application suites.
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @oxog/vld
26
+ # or
27
+ yarn add @oxog/vld
28
+ # or
29
+ pnpm add @oxog/vld
30
+ # or
31
+ bun add @oxog/vld
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ```typescript
39
+ import { v } from '@oxog/vld';
40
+
41
+ // Define schema with chainable validations
42
+ const userSchema = v.object({
43
+ name: v.string().min(2).max(100),
44
+ email: v.string().email(),
45
+ age: v.number().int().positive().optional(),
46
+ role: v.enum('admin', 'user', 'guest').default('user'),
47
+ tags: v.array(v.string()).min(1),
48
+ });
49
+
50
+ // Infer TypeScript type
51
+ type User = v.infer<typeof userSchema>;
52
+
53
+ // Safe parsing (no throwing)
54
+ const result = userSchema.safeParse({
55
+ name: 'John Doe',
56
+ email: 'john@example.com',
57
+ age: 28,
58
+ tags: ['developer', 'typescript'],
59
+ });
60
+
61
+ if (result.success) {
62
+ console.log('Valid data:', result.data); // Typed as User
63
+ } else {
64
+ console.error('Validation issues:', result.error.issues);
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Core Schema API
71
+
72
+ ### Primitive Validators
73
+
74
+ ```typescript
75
+ v.string() // String validation
76
+ v.number() // Number validation
77
+ v.int() // Integer validation
78
+ v.int32() // 32-bit integer validation
79
+ v.boolean() // Boolean validation
80
+ v.bigint() // BigInt validation
81
+ v.date() // Date validation
82
+ v.symbol() // Symbol validation
83
+ v.uint8array() // Uint8Array validation
84
+ v.literal('active') // Literal value
85
+ v.enum('admin', 'user', 'guest') // Enum values
86
+ v.any() // Any type
87
+ v.unknown() // Unknown type
88
+ v.null() // Null
89
+ v.undefined() // Undefined
90
+ v.nullish() // Null or undefined
91
+ v.void() // Void
92
+ v.never() // Never
93
+ ```
94
+
95
+ ### String Formats
96
+
97
+ ```typescript
98
+ v.string()
99
+ .min(3)
100
+ .max(100)
101
+ .email()
102
+ .url()
103
+ .uuid()
104
+ .regex(/^[a-z0-9]+$/)
105
+ .startsWith('https://')
106
+ .endsWith('.json')
107
+ .trim()
108
+ .toLowerCase();
109
+
110
+ // Top-level format helpers:
111
+ v.email()
112
+ v.uuid()
113
+ v.creditCard() // Luhn checksum validated
114
+ v.jwt()
115
+ v.cuid()
116
+ v.cuid2()
117
+ v.nanoid()
118
+ v.ulid()
119
+ v.ipv4()
120
+ v.ipv6()
121
+ v.iso.date()
122
+ v.iso.dateTime()
123
+ ```
124
+
125
+ ### Number Constraints
126
+
127
+ ```typescript
128
+ v.number()
129
+ .min(0)
130
+ .max(100)
131
+ .int()
132
+ .positive()
133
+ .negative()
134
+ .nonnegative()
135
+ .multipleOf(5)
136
+ .finite()
137
+ .safe();
138
+ ```
139
+
140
+ ### Objects & Collections
141
+
142
+ ```typescript
143
+ // Objects
144
+ const profileSchema = v.object({
145
+ username: v.string().min(3),
146
+ age: v.number().optional(),
147
+ });
148
+
149
+ // Object transformations
150
+ profileSchema.partial(); // All fields optional
151
+ profileSchema.strict(); // Reject unknown fields
152
+ profileSchema.passthrough(); // Keep unknown fields
153
+ profileSchema.pick('username');
154
+ profileSchema.omit('age');
155
+ profileSchema.extend({ bio: v.string() });
156
+
157
+ // Arrays & Collections
158
+ v.array(v.string()).min(1).max(10);
159
+ v.tuple(v.string(), v.number());
160
+ v.record(v.string(), v.number());
161
+ v.set(v.string());
162
+ v.map(v.string(), v.number());
163
+ ```
164
+
165
+ ### Unions & Compositions
166
+
167
+ ```typescript
168
+ // Union
169
+ v.union(v.string(), v.number());
170
+
171
+ // Discriminated Union
172
+ const eventSchema = v.discriminatedUnion('type',
173
+ v.object({ type: v.literal('click'), x: v.number(), y: v.number() }),
174
+ v.object({ type: v.literal('scroll'), offset: v.number() })
175
+ );
176
+
177
+ // Intersections & XOR
178
+ v.intersection(schemaA, schemaB);
179
+ v.xor(schemaA, schemaB);
180
+
181
+ // Recursive / Lazy Schemas
182
+ const treeSchema: ReturnType<typeof v.lazy> = v.lazy(() =>
183
+ v.object({
184
+ id: v.string(),
185
+ children: v.array(treeSchema).optional(),
186
+ })
187
+ );
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Type Coercion & Modifiers
193
+
194
+ ### Automatic Coercion (`v.coerce`)
195
+
196
+ ```typescript
197
+ v.coerce.string().parse(123); // "123"
198
+ v.coerce.number().parse("42"); // 42
199
+ v.coerce.boolean().parse("true"); // true
200
+ v.coerce.bigint().parse("1000"); // 1000n
201
+ v.coerce.date().parse("2026-08-17"); // Date object
202
+ ```
203
+
204
+ ### Refinements, Transforms & Defaults
205
+
206
+ ```typescript
207
+ const customSchema = v.string()
208
+ .transform(val => val.trim())
209
+ .refine(val => val.length >= 3, 'Must be at least 3 characters')
210
+ .default('default_value')
211
+ .catch('fallback_on_error');
212
+
213
+ // SuperRefine for multi-field cross validation
214
+ const passwordSchema = v.object({
215
+ password: v.string().min(8),
216
+ confirm: v.string(),
217
+ }).superRefine((data, ctx) => {
218
+ if (data.password !== data.confirm) {
219
+ ctx.addIssue({
220
+ code: 'custom',
221
+ path: ['confirm'],
222
+ message: 'Passwords do not match',
223
+ });
224
+ }
225
+ });
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Tree-Shakeable Mini API
231
+
232
+ For bundle-constrained applications, `@oxog/vld/mini` provides pure standalone functions with zero extra overhead:
233
+
234
+ ```typescript
235
+ import { string, number, object, optional, array } from '@oxog/vld/mini';
236
+
237
+ const userSchema = object({
238
+ name: string().min(2),
239
+ age: optional(number().positive()),
240
+ roles: array(string()),
241
+ });
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Drop-in Zod Compatibility
247
+
248
+ VLD provides drop-in subpaths that mirror Zod export structures and error shapes:
249
+
250
+ ```typescript
251
+ // Replace Zod imports seamlessly
252
+ import { z } from '@oxog/vld';
253
+ import * as core from '@oxog/vld/v4/core';
254
+ import * as mini from '@oxog/vld/v4-mini';
255
+ import * as locales from '@oxog/vld/v4/locales';
256
+
257
+ import { v, deepPartial, input, output } from '@oxog/vld';
258
+ ```
259
+
260
+ - Structured error issues with `expected`, `received`, `minimum`, `maximum`, and `path`.
261
+ - Compatibility tested against latest stable Zod releases.
262
+
263
+ ---
264
+
265
+ ## Error Handling & Formatting
266
+
267
+ ```typescript
268
+ import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
269
+
270
+ const result = userSchema.safeParse(invalidData);
271
+
272
+ if (!result.success) {
273
+ const error = result.error as VldError;
274
+
275
+ // Flattened field errors for forms
276
+ const { fieldErrors, formErrors } = flattenError(error);
277
+
278
+ // Human-readable CLI / console output
279
+ const pretty = prettifyError(error);
280
+
281
+ // Nested tree structure for UI inspection
282
+ const tree = treeifyError(error);
283
+ }
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Internationalization (i18n)
289
+
290
+ VLD includes built-in translations for 27+ languages:
291
+
292
+ ```typescript
293
+ import { v, setLocale } from '@oxog/vld';
294
+
295
+ setLocale('tr'); // Turkish error messages
296
+ setLocale('es'); // Spanish
297
+ setLocale('de'); // German
298
+ setLocale('ja'); // Japanese
299
+ setLocale('fr'); // French
300
+ ```
301
+
302
+ ### Lazy Loading for Minimal Bundles
303
+
304
+ ```typescript
305
+ import { setLocaleAsync, preloadLocales } from '@oxog/vld/locales/lazy';
306
+
307
+ // Loads locale on demand via dynamic import()
308
+ await setLocaleAsync('tr');
309
+
310
+ // Preload for SSR / warm start
311
+ await preloadLocales(['en', 'de', 'ja']);
312
+ ```
313
+
314
+ ---
315
+
316
+ ## Bidirectional Codecs
317
+
318
+ ```typescript
319
+ import { stringToNumber, jsonCodec, base64ToBytes, hexToBytes } from '@oxog/vld';
320
+
321
+ // String to Number decode & encode
322
+ const num = stringToNumber.parse('42'); // 42
323
+ const str = stringToNumber.encode(42); // "42"
324
+
325
+ // JSON codec
326
+ const json = jsonCodec();
327
+ const parsed = json.parse('{"id":1}');
328
+ const encoded = json.encode(parsed);
329
+
330
+ // Binary conversions
331
+ const bytes = base64ToBytes.parse('SGVsbG8=');
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Result Pattern
337
+
338
+ Functional error handling without exceptions:
339
+
340
+ ```typescript
341
+ import { Ok, Err, match, map, flatMap, tryCatch, isOk, isErr, unwrapOr } from '@oxog/vld';
342
+
343
+ const result = tryCatch(() => JSON.parse(rawInput));
344
+
345
+ const output = match(result, {
346
+ ok: data => `Success: ${data.id}`,
347
+ err: err => `Failed: ${err.message}`,
348
+ });
349
+ ```
350
+
351
+ ---
352
+
353
+ ## Plugin System
354
+
355
+ ```typescript
356
+ import { definePlugin, usePlugin, createVldKernel, v } from '@oxog/vld';
357
+
358
+ const phonePlugin = definePlugin({
359
+ name: 'phone-validator',
360
+ version: '1.0.0',
361
+ validators: {
362
+ phone: () => v.string().regex(/^\+?[1-9]\d{1,14}$/),
363
+ },
364
+ });
365
+
366
+ usePlugin(phonePlugin);
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Performance
372
+
373
+ VLD is optimized for modern V8 runtimes. CI gates enforce performance floors on every commit against Zod:
374
+
375
+ | Benchmark Case | VLD Throughput | Relative Speedup |
376
+ |----------------|----------------|------------------|
377
+ | Nullish Parse | ~214M ops/sec | **30.7x faster** |
378
+ | Number / Positive Int | ~253M ops/sec | **9.1x faster** |
379
+ | Discriminated Union | ~35M ops/sec | **4.1x faster** |
380
+ | Optional Parse | ~213M ops/sec | **3.8x faster** |
381
+ | Union Parse | ~39M ops/sec | **3.3x faster** |
382
+ | Simple String | ~620M ops/sec | **3.0x faster** |
383
+ | Array / Object Parse | ~49M ops/sec | **1.7x faster** |
384
+
385
+ Explore full benchmark results and interactive visual comparisons at [vld.oxog.dev/benchmark](https://vld.oxog.dev/benchmark).
386
+
387
+ ### Running Benchmarks Locally
388
+
389
+ ```bash
390
+ npm run benchmark
391
+ npm run benchmark:guard
392
+ npm run benchmark:memory
393
+ npm run benchmark:startup
394
+ npm run release:check
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Contributing
400
+
401
+ Contributions are warmly welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md) for details.
402
+
403
+ ---
404
+
405
+ ## Links
406
+
407
+ - **Documentation & Playground**: [https://vld.oxog.dev](https://vld.oxog.dev)
408
+ - **NPM Package**: [https://www.npmjs.com/package/@oxog/vld](https://www.npmjs.com/package/@oxog/vld)
409
+ - **GitHub Repository**: [https://github.com/ersinkoc/vld](https://github.com/ersinkoc/vld)
410
+
411
+ ---
412
+
413
+ Made with Love by [Ersin KOC](https://github.com/ersinkoc)