@oxog/vld 1.5.0 → 2.0.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.
Files changed (279) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +558 -517
  3. package/dist/chunks/bigint-ZKkWLdmi.js +1628 -0
  4. package/dist/chunks/bigint-ZKkWLdmi.js.map +1 -0
  5. package/dist/{coercion/string.js → chunks/date-7Iz2BGsL.js} +271 -5
  6. package/dist/chunks/date-7Iz2BGsL.js.map +1 -0
  7. package/dist/chunks/index-BoV-4S1F.js +894 -0
  8. package/dist/chunks/index-BoV-4S1F.js.map +1 -0
  9. package/dist/chunks/index-eWXdjyyy.js +426 -0
  10. package/dist/chunks/index-eWXdjyyy.js.map +1 -0
  11. package/dist/chunks/json-nIhyRPOU.js +1934 -0
  12. package/dist/chunks/json-nIhyRPOU.js.map +1 -0
  13. package/dist/{validators/unknown.js → chunks/unknown-CjSRcELI.js} +6 -3
  14. package/dist/chunks/unknown-CjSRcELI.js.map +1 -0
  15. package/dist/cjs/errors.cjs +387 -0
  16. package/dist/cjs/errors.cjs.map +1 -0
  17. package/dist/cjs/index.cjs +9815 -0
  18. package/dist/cjs/index.cjs.map +1 -0
  19. package/dist/cjs/locales/index.cjs +2877 -0
  20. package/dist/cjs/locales/index.cjs.map +1 -0
  21. package/dist/cjs/locales/lazy.cjs +3169 -0
  22. package/dist/cjs/locales/lazy.cjs.map +1 -0
  23. package/dist/cjs/mini.cjs +7161 -0
  24. package/dist/cjs/mini.cjs.map +1 -0
  25. package/dist/codecs/index.js +4 -275
  26. package/dist/codecs/index.js.map +1 -1
  27. package/dist/coercion/index.d.ts +11 -0
  28. package/dist/coercion/index.d.ts.map +1 -0
  29. package/dist/coercion/{bigint.js → index.js} +7 -4
  30. package/dist/coercion/index.js.map +1 -0
  31. package/dist/compat/emitter.js +6 -4
  32. package/dist/compat/emitter.js.map +1 -1
  33. package/dist/compat/result.js +21 -19
  34. package/dist/compat/result.js.map +1 -1
  35. package/dist/errors.js +13 -10
  36. package/dist/errors.js.map +1 -1
  37. package/dist/index.js +225 -126
  38. package/dist/index.js.map +1 -1
  39. package/dist/kernel.js +10 -7
  40. package/dist/kernel.js.map +1 -1
  41. package/dist/locales/af.js +4 -2
  42. package/dist/locales/af.js.map +1 -1
  43. package/dist/locales/ar.js +4 -2
  44. package/dist/locales/ar.js.map +1 -1
  45. package/dist/locales/bn.js +4 -2
  46. package/dist/locales/bn.js.map +1 -1
  47. package/dist/locales/da.js +4 -2
  48. package/dist/locales/da.js.map +1 -1
  49. package/dist/locales/de.js +4 -2
  50. package/dist/locales/de.js.map +1 -1
  51. package/dist/locales/en.js +4 -2
  52. package/dist/locales/en.js.map +1 -1
  53. package/dist/locales/es-MX.js +4 -2
  54. package/dist/locales/es-MX.js.map +1 -1
  55. package/dist/locales/es.js +4 -2
  56. package/dist/locales/es.js.map +1 -1
  57. package/dist/locales/fi.js +4 -2
  58. package/dist/locales/fi.js.map +1 -1
  59. package/dist/locales/fr.js +4 -2
  60. package/dist/locales/fr.js.map +1 -1
  61. package/dist/locales/hi.js +4 -2
  62. package/dist/locales/hi.js.map +1 -1
  63. package/dist/locales/id.js +4 -2
  64. package/dist/locales/id.js.map +1 -1
  65. package/dist/locales/index.js +3 -91
  66. package/dist/locales/index.js.map +1 -1
  67. package/dist/locales/it.js +4 -2
  68. package/dist/locales/it.js.map +1 -1
  69. package/dist/locales/ja.js +4 -2
  70. package/dist/locales/ja.js.map +1 -1
  71. package/dist/locales/ko.js +4 -2
  72. package/dist/locales/ko.js.map +1 -1
  73. package/dist/locales/lazy.d.ts +111 -0
  74. package/dist/locales/lazy.d.ts.map +1 -0
  75. package/dist/locales/lazy.js +220 -0
  76. package/dist/locales/lazy.js.map +1 -0
  77. package/dist/locales/nl.js +4 -2
  78. package/dist/locales/nl.js.map +1 -1
  79. package/dist/locales/no.js +4 -2
  80. package/dist/locales/no.js.map +1 -1
  81. package/dist/locales/pl.js +4 -2
  82. package/dist/locales/pl.js.map +1 -1
  83. package/dist/locales/pt-BR.js +4 -2
  84. package/dist/locales/pt-BR.js.map +1 -1
  85. package/dist/locales/pt.js +4 -2
  86. package/dist/locales/pt.js.map +1 -1
  87. package/dist/locales/ru.js +4 -2
  88. package/dist/locales/ru.js.map +1 -1
  89. package/dist/locales/sv.js +4 -2
  90. package/dist/locales/sv.js.map +1 -1
  91. package/dist/locales/sw.js +4 -2
  92. package/dist/locales/sw.js.map +1 -1
  93. package/dist/locales/th.js +4 -2
  94. package/dist/locales/th.js.map +1 -1
  95. package/dist/locales/tr.js +4 -2
  96. package/dist/locales/tr.js.map +1 -1
  97. package/dist/locales/vi.js +4 -2
  98. package/dist/locales/vi.js.map +1 -1
  99. package/dist/locales/zh.js +4 -2
  100. package/dist/locales/zh.js.map +1 -1
  101. package/dist/mini.d.ts +182 -0
  102. package/dist/mini.d.ts.map +1 -0
  103. package/dist/mini.js +132 -0
  104. package/dist/mini.js.map +1 -0
  105. package/dist/pigment.js +8 -7
  106. package/dist/pigment.js.map +1 -1
  107. package/dist/validators/index.js +5 -45
  108. package/dist/validators/index.js.map +1 -1
  109. package/package.json +69 -11
  110. package/dist/cli/benchmark.d.ts +0 -15
  111. package/dist/cli/benchmark.d.ts.map +0 -1
  112. package/dist/cli/benchmark.js +0 -248
  113. package/dist/cli/benchmark.js.map +0 -1
  114. package/dist/cli/bin.js +0 -35
  115. package/dist/cli/bin.js.map +0 -1
  116. package/dist/cli/commands/benchmark.js +0 -204
  117. package/dist/cli/commands/benchmark.js.map +0 -1
  118. package/dist/cli/commands/validate.js +0 -157
  119. package/dist/cli/commands/validate.js.map +0 -1
  120. package/dist/cli/generate.d.ts +0 -14
  121. package/dist/cli/generate.d.ts.map +0 -1
  122. package/dist/cli/generate.js +0 -233
  123. package/dist/cli/generate.js.map +0 -1
  124. package/dist/cli/index.js +0 -182
  125. package/dist/cli/index.js.map +0 -1
  126. package/dist/cli/validate.d.ts +0 -15
  127. package/dist/cli/validate.d.ts.map +0 -1
  128. package/dist/cli/validate.js +0 -162
  129. package/dist/cli/validate.js.map +0 -1
  130. package/dist/coercion/bigint.js.map +0 -1
  131. package/dist/coercion/boolean.js +0 -59
  132. package/dist/coercion/boolean.js.map +0 -1
  133. package/dist/coercion/date.js +0 -52
  134. package/dist/coercion/date.js.map +0 -1
  135. package/dist/coercion/number.js +0 -160
  136. package/dist/coercion/number.js.map +0 -1
  137. package/dist/coercion/string.js.map +0 -1
  138. package/dist/compat/index.js +0 -14
  139. package/dist/compat/index.js.map +0 -1
  140. package/dist/events.js +0 -8
  141. package/dist/events.js.map +0 -1
  142. package/dist/guards.d.ts +0 -143
  143. package/dist/guards.d.ts.map +0 -1
  144. package/dist/guards.js +0 -238
  145. package/dist/guards.js.map +0 -1
  146. package/dist/index-new.d.ts.map +0 -1
  147. package/dist/locales/backup-en.js +0 -105
  148. package/dist/locales/backup-en.js.map +0 -1
  149. package/dist/locales/types.js +0 -2
  150. package/dist/locales/types.js.map +0 -1
  151. package/dist/locales.d.ts +0 -54
  152. package/dist/locales.d.ts.map +0 -1
  153. package/dist/locales.js +0 -732
  154. package/dist/locales.js.map +0 -1
  155. package/dist/logger.js +0 -184
  156. package/dist/logger.js.map +0 -1
  157. package/dist/plugins/codecs.d.ts +0 -17
  158. package/dist/plugins/codecs.d.ts.map +0 -1
  159. package/dist/plugins/codecs.js +0 -29
  160. package/dist/plugins/codecs.js.map +0 -1
  161. package/dist/plugins/coercion.d.ts +0 -13
  162. package/dist/plugins/coercion.d.ts.map +0 -1
  163. package/dist/plugins/coercion.js +0 -34
  164. package/dist/plugins/coercion.js.map +0 -1
  165. package/dist/plugins/core-validators.d.ts +0 -13
  166. package/dist/plugins/core-validators.d.ts.map +0 -1
  167. package/dist/plugins/core-validators.js +0 -96
  168. package/dist/plugins/core-validators.js.map +0 -1
  169. package/dist/plugins/index.js +0 -8
  170. package/dist/plugins/index.js.map +0 -1
  171. package/dist/plugins/kernel.d.ts +0 -29
  172. package/dist/plugins/kernel.d.ts.map +0 -1
  173. package/dist/plugins/kernel.js +0 -486
  174. package/dist/plugins/kernel.js.map +0 -1
  175. package/dist/plugins/types.js +0 -8
  176. package/dist/plugins/types.js.map +0 -1
  177. package/dist/style.d.ts +0 -123
  178. package/dist/style.d.ts.map +0 -1
  179. package/dist/style.js +0 -369
  180. package/dist/style.js.map +0 -1
  181. package/dist/utils/codec-utils.js +0 -229
  182. package/dist/utils/codec-utils.js.map +0 -1
  183. package/dist/utils/deep-merge.js +0 -76
  184. package/dist/utils/deep-merge.js.map +0 -1
  185. package/dist/utils/ip-validation.js +0 -98
  186. package/dist/utils/ip-validation.js.map +0 -1
  187. package/dist/utils/security.js +0 -61
  188. package/dist/utils/security.js.map +0 -1
  189. package/dist/validators/any.js +0 -25
  190. package/dist/validators/any.js.map +0 -1
  191. package/dist/validators/array.js +0 -190
  192. package/dist/validators/array.js.map +0 -1
  193. package/dist/validators/base.js +0 -499
  194. package/dist/validators/base.js.map +0 -1
  195. package/dist/validators/base64.js +0 -65
  196. package/dist/validators/base64.js.map +0 -1
  197. package/dist/validators/bigint.js +0 -142
  198. package/dist/validators/bigint.js.map +0 -1
  199. package/dist/validators/boolean.js +0 -114
  200. package/dist/validators/boolean.js.map +0 -1
  201. package/dist/validators/codec.js +0 -182
  202. package/dist/validators/codec.js.map +0 -1
  203. package/dist/validators/custom.js +0 -50
  204. package/dist/validators/custom.js.map +0 -1
  205. package/dist/validators/date.js +0 -227
  206. package/dist/validators/date.js.map +0 -1
  207. package/dist/validators/discriminated-union.js +0 -98
  208. package/dist/validators/discriminated-union.js.map +0 -1
  209. package/dist/validators/enum.js +0 -82
  210. package/dist/validators/enum.js.map +0 -1
  211. package/dist/validators/file.js +0 -114
  212. package/dist/validators/file.js.map +0 -1
  213. package/dist/validators/function.js +0 -45
  214. package/dist/validators/function.js.map +0 -1
  215. package/dist/validators/hex.js +0 -62
  216. package/dist/validators/hex.js.map +0 -1
  217. package/dist/validators/intersection.js +0 -64
  218. package/dist/validators/intersection.js.map +0 -1
  219. package/dist/validators/json.js +0 -64
  220. package/dist/validators/json.js.map +0 -1
  221. package/dist/validators/lazy.js +0 -42
  222. package/dist/validators/lazy.js.map +0 -1
  223. package/dist/validators/literal.js +0 -45
  224. package/dist/validators/literal.js.map +0 -1
  225. package/dist/validators/map.js +0 -54
  226. package/dist/validators/map.js.map +0 -1
  227. package/dist/validators/nan.js +0 -32
  228. package/dist/validators/nan.js.map +0 -1
  229. package/dist/validators/never.js +0 -29
  230. package/dist/validators/never.js.map +0 -1
  231. package/dist/validators/null.js +0 -31
  232. package/dist/validators/null.js.map +0 -1
  233. package/dist/validators/number.js +0 -225
  234. package/dist/validators/number.js.map +0 -1
  235. package/dist/validators/object-optimized.d.ts +0 -23
  236. package/dist/validators/object-optimized.d.ts.map +0 -1
  237. package/dist/validators/object-optimized.js +0 -179
  238. package/dist/validators/object-optimized.js.map +0 -1
  239. package/dist/validators/object-ultra.d.ts +0 -34
  240. package/dist/validators/object-ultra.d.ts.map +0 -1
  241. package/dist/validators/object-ultra.js +0 -175
  242. package/dist/validators/object-ultra.js.map +0 -1
  243. package/dist/validators/object.js +0 -458
  244. package/dist/validators/object.js.map +0 -1
  245. package/dist/validators/record.js +0 -128
  246. package/dist/validators/record.js.map +0 -1
  247. package/dist/validators/set.js +0 -51
  248. package/dist/validators/set.js.map +0 -1
  249. package/dist/validators/string-bool.js +0 -127
  250. package/dist/validators/string-bool.js.map +0 -1
  251. package/dist/validators/string-formats.js +0 -120
  252. package/dist/validators/string-formats.js.map +0 -1
  253. package/dist/validators/string-ultra.d.ts +0 -49
  254. package/dist/validators/string-ultra.d.ts.map +0 -1
  255. package/dist/validators/string-ultra.js +0 -217
  256. package/dist/validators/string-ultra.js.map +0 -1
  257. package/dist/validators/string.js +0 -253
  258. package/dist/validators/string.js.map +0 -1
  259. package/dist/validators/symbol.js +0 -42
  260. package/dist/validators/symbol.js.map +0 -1
  261. package/dist/validators/template-literal.js +0 -102
  262. package/dist/validators/template-literal.js.map +0 -1
  263. package/dist/validators/tuple.js +0 -55
  264. package/dist/validators/tuple.js.map +0 -1
  265. package/dist/validators/uint8array.js +0 -98
  266. package/dist/validators/uint8array.js.map +0 -1
  267. package/dist/validators/undefined.js +0 -31
  268. package/dist/validators/undefined.js.map +0 -1
  269. package/dist/validators/union-optimized.d.ts +0 -15
  270. package/dist/validators/union-optimized.d.ts.map +0 -1
  271. package/dist/validators/union-optimized.js +0 -92
  272. package/dist/validators/union-optimized.js.map +0 -1
  273. package/dist/validators/union.js +0 -126
  274. package/dist/validators/union.js.map +0 -1
  275. package/dist/validators/unknown.js.map +0 -1
  276. package/dist/validators/void.js +0 -35
  277. package/dist/validators/void.js.map +0 -1
  278. package/dist/validators/xor.js +0 -64
  279. package/dist/validators/xor.js.map +0 -1
package/README.md CHANGED
@@ -1,75 +1,164 @@
1
1
  # VLD - Fast & Lightweight TypeScript Validation Library
2
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-96.55%25-brightgreen.svg)](package.json)
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-99.23%25-brightgreen.svg)](package.json)
4
4
 
5
5
  VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScript with **full Zod feature parity**. Built with performance in mind, it provides a simple and intuitive API while maintaining excellent type inference and 27+ language internationalization support.
6
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](#️-error-handling--formatting)
16
- - [🔥 Advanced Examples](#-advanced-examples)
17
- - [🎯 Why VLD?](#-why-vld)
18
- - [🔄 Codecs - Bidirectional Transformations](#-codecs---bidirectional-transformations)
19
- - [🔄 Migrating from Zod](#-migrating-from-zod)
20
- - [📈 Benchmarks](#-benchmarks)
21
- - [🤝 Contributing](#-contributing)
22
- - [🔗 Links](#-links)
23
-
24
- ## 🚀 Features
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
25
28
 
26
29
  ### Core Features
27
- - **⚡ Blazing Fast**: Optimized for V8 engine with superior performance
28
- - **🎯 Type-Safe**: Full TypeScript support with excellent type inference
29
- - **📦 Zero Dependencies**: Lightweight with no external dependencies
30
- - **🌳 Tree-Shakeable**: Only import what you need
31
- - **🔧 Composable**: Chain validations for complex schemas
32
- - **⚠️ Advanced Error Formatting**: Tree, pretty, and flatten error utilities
33
- - **🌍 Multi-language**: Built-in support for 27+ languages
34
- - **✅ 96.55% Test Coverage**: Rigorously tested with 1142 passing tests
35
- - **🏆 Industry Leading Performance**: 2.52x faster than Zod on average
36
-
37
- ### Advanced Zod-Compatible Features
38
- - **🔄 Type Coercion**: `v.coerce.string()`, `v.coerce.number()`, `v.coerce.boolean()`, etc.
39
- - **📊 Advanced Types**: BigInt, Symbol, Tuple, Record, Set, Map validation
40
- - **⚡ Intersection Types**: Combine multiple schemas with intelligent merging
41
- - **🎨 Custom Validation**: `refine()` for custom predicates and validation logic
42
- - **🔄 Data Transformation**: `transform()` for post-validation data transformation
43
- - **🏠 Default Values**: `default()` for handling undefined inputs elegantly
44
- - **🛡️ Fallback Handling**: `catch()` for graceful error recovery
45
- - **🎯 Object Utilities**: `pick()`, `omit()`, `extend()` for flexible object schemas
46
-
47
- ### 🚀 **NEW in v1.4.0** - Zod 4 Full API Parity
48
- - **🌐 `v.cidrv6()`**: IPv6 CIDR block validation
49
- - **🔗 `.apply()`**: External function chaining for advanced composition
50
- - **🛡️ `.safeExtend()`**: Type-safe object extension without accidental overrides
51
-
52
- ### 🚀 Codec System - Beyond Zod
53
- - **↔️ Bidirectional Transformations**: Full encode/decode support for data conversion
54
- - **📦 19 Built-in Codecs**: String conversions, date parsing, JSON, URL, binary data
55
- - **🔗 Zod-Compatible**: All `stringToNumber`, `jsonCodec`, `base64ToBytes`, etc.
56
- - **⚡ Async Support**: Both sync and async codec operations
57
- - **🛠 Custom Codecs**: Create your own bidirectional transformations
58
- - **🎯 Type-Safe**: Full TypeScript support with perfect type inference
59
-
60
- ## 📊 Performance
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
+ - **99.23% Test Coverage**: Rigorously tested with 1858 passing tests
38
+ - **Industry Leading Performance**: 1.98x faster than Zod on average
39
+
40
+ ### Advanced Zod-Compatible Features
41
+ - **Type Coercion**: `v.coerce.string()`, `v.coerce.number()`, `v.coerce.boolean()`, etc.
42
+ - **Advanced Types**: BigInt, Symbol, Tuple, Record, Set, Map validation
43
+ - **Intersection Types**: Combine multiple schemas with intelligent merging
44
+ - **Custom Validation**: `refine()` for custom predicates and validation logic
45
+ - **Data Transformation**: `transform()` for post-validation data transformation
46
+ - **Default Values**: `default()` for handling undefined inputs elegantly
47
+ - **Fallback Handling**: `catch()` for graceful error recovery
48
+ - **Object Utilities**: `pick()`, `omit()`, `extend()` for flexible object schemas
49
+
50
+ ### NEW in v2.0.0 - Modular Architecture
51
+
52
+ #### Tree-Shakable Mini API
53
+ ```typescript
54
+ import { string, number, object, optional } from '@oxog/vld/mini';
55
+
56
+ const schema = object({
57
+ name: string().min(1),
58
+ age: optional(number().positive()),
59
+ });
60
+ ```
61
+ - **82% smaller bundles** when using only needed validators
62
+ - Individual factory functions for optimal tree-shaking
63
+ - Full TypeScript support with identical type inference
64
+
65
+ #### Lazy Locale Loading
66
+ ```typescript
67
+ import { setLocaleAsync } from '@oxog/vld/locales';
68
+ await setLocaleAsync('tr'); // Loads Turkish on demand
69
+ ```
70
+ - **92% bundle reduction** - Only English bundled by default
71
+ - `preloadLocales()` for SSR/batch loading
72
+ - Full backwards compatibility with `setLocale()`
73
+
74
+ #### Dual ESM/CJS Build
75
+ - ESM builds for modern bundlers (Vite, esbuild)
76
+ - CJS builds for Node.js and legacy environments
77
+ - Proper `exports` field with conditional exports
78
+
79
+ ### NEW in v1.5.0 - Major Platform Release
80
+
81
+ #### Plugin System
82
+ - **`definePlugin()`**: Create custom plugins with validators, transforms, and codecs
83
+ - **`usePlugin()`**: Register plugins globally
84
+ - **Plugin Hooks**: Lifecycle hooks for validation events
85
+ - **Custom Validators**: Extend VLD with your own validators
86
+
87
+ #### Result Pattern
88
+ - **`Ok()`/`Err()`**: Functional error handling
89
+ - **`match()`**: Pattern matching on results
90
+ - **`map()`/`flatMap()`**: Transform results
91
+ - **`tryCatch()`**: Safe function execution
92
+ - **`all()`**: Combine multiple results
93
+
94
+ #### Event System
95
+ - **`createEmitter()`**: Type-safe event emitter
96
+ - **`createEventBus()`**: Global event bus
97
+ - **Validation Events**: Parse start, success, error, field validation
98
+
99
+ #### CLI Tools
100
+ - **`vld validate`**: Validate data from command line
101
+ - **`vld benchmark`**: Run performance benchmarks
102
+ - **Colored Output**: Beautiful terminal output with pigment
103
+
104
+ #### New Validators
105
+ - **`v.discriminatedUnion()`**: Discriminated union types
106
+ - **`v.xor()`**: Exclusive OR validation
107
+ - **`v.file()`**: File upload validation
108
+ - **`v.function()`**: Function validation
109
+ - **`v.custom()`**: Type-safe custom validators
110
+ - **`v.json()`**: JSON string validation with schema
111
+ - **`v.lazy()`**: Recursive schema support
112
+ - **`v.nan()`**: NaN validation
113
+ - **`v.null()`**: Null validation
114
+ - **`v.undefined()`**: Undefined validation
115
+ - **`v.templateLiteral()`**: Template literal types
116
+
117
+ #### New String Format Validators
118
+ - **`v.hostname()`**: Hostname validation
119
+ - **`v.emoji()`**: Emoji validation
120
+ - **`v.base64()`/`v.base64url()`**: Base64 format validation
121
+ - **`v.hex()`**: Hex string validation
122
+ - **`v.jwt()`**: JWT format validation
123
+ - **`v.nanoid()`/`v.cuid()`/`v.cuid2()`/`v.ulid()`**: ID format validation
124
+ - **`v.mac()`**: MAC address validation
125
+ - **`v.cidrv4()`/`v.cidrv6()`**: CIDR block validation
126
+ - **`v.e164()`**: E.164 phone number validation
127
+ - **`v.hash()`**: Hash validation (md5, sha1, sha256, sha384, sha512)
128
+ - **`v.iso.date()`/`v.iso.time()`/`v.iso.dateTime()`/`v.iso.duration()`**: ISO format validation
129
+
130
+ #### Enhanced Object Utilities
131
+ - **`v.strictObject()`**: Strict mode object validation
132
+ - **`v.looseObject()`**: Passthrough object validation
133
+ - **`v.partialRecord()`**: Partial record validation
134
+ - **`v.looseRecord()`**: Loose record validation
135
+ - **`v.int()`**: Integer shortcut
136
+ - **`v.int32()`**: 32-bit integer shortcut
137
+ - **`v.nullish()`**: Null or undefined
138
+ - **`v.NEVER`**: NEVER constant for transforms (Zod 4 parity)
139
+
140
+ ### Codec System - Beyond Zod
141
+ - **Bidirectional Transformations**: Full encode/decode support for data conversion
142
+ - **19 Built-in Codecs**: String conversions, date parsing, JSON, URL, binary data
143
+ - **Zod-Compatible**: All `stringToNumber`, `jsonCodec`, `base64ToBytes`, etc.
144
+ - **Async Support**: Both sync and async codec operations
145
+ - **Custom Codecs**: Create your own bidirectional transformations
146
+ - **Type-Safe**: Full TypeScript support with perfect type inference
147
+
148
+ ## Performance
61
149
 
62
150
  VLD is designed for speed and efficiency with recent optimizations delivering exceptional performance:
63
151
 
64
- ### Speed Benchmarks (v1.0.0 - Optimized)
65
- - **4.6x faster** for number validation with constraints
66
- - **3.6x faster** for union type validation
67
- - **2.5x faster** for email validation
68
- - **1.9x faster** for array validation
69
- - **1.7x faster** for primitive string validation
70
- - **2.8x faster** overall average performance
152
+ ### Speed Benchmarks (v1.5.0)
153
+ - **3.25x faster** for email validation
154
+ - **3.23x faster** for number validation
155
+ - **3.16x faster** for optional validation
156
+ - **2.73x faster** for safeParse operations
157
+ - **2.08x faster** for enum validation
158
+ - **2.03x faster** for simple string validation
159
+ - **1.98x faster** overall average performance
71
160
 
72
- ### Recent Optimizations (v1.0.0)
161
+ ### Optimizations
73
162
  - **110x improvement** in union type validation
74
163
  - **Simplified email regex** for maximum performance
75
164
  - **Inline type checks** in object validation
@@ -112,7 +201,7 @@ When testing real-world patterns:
112
201
 
113
202
  Run `npm run benchmark:truth` to see the real performance difference.
114
203
 
115
- ## 📦 Installation
204
+ ## Installation
116
205
 
117
206
  ```bash
118
207
  npm install @oxog/vld
@@ -122,7 +211,7 @@ yarn add @oxog/vld
122
211
  pnpm add @oxog/vld
123
212
  ```
124
213
 
125
- ## 🎯 Quick Start
214
+ ## Quick Start
126
215
 
127
216
  ```typescript
128
217
  import { v } from '@oxog/vld';
@@ -158,13 +247,15 @@ For advanced error formatting:
158
247
  import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
159
248
  ```
160
249
 
161
- ## 📖 API Reference
250
+ ## API Reference
162
251
 
163
252
  ### Basic Types
164
253
 
165
254
  ```typescript
166
255
  v.string() // String validation
167
- v.number() // Number validation
256
+ v.number() // Number validation
257
+ v.int() // Integer validation (shortcut)
258
+ v.int32() // 32-bit integer validation
168
259
  v.boolean() // Boolean validation
169
260
  v.bigint() // BigInt validation
170
261
  v.symbol() // Symbol validation
@@ -173,9 +264,12 @@ v.uint8array()// Uint8Array validation
173
264
  v.literal() // Literal values
174
265
  v.enum() // Enum values (supports TypeScript enums)
175
266
  v.any() // Any type
176
- v.unknown() // Unknown type
267
+ v.unknown() // Unknown type
177
268
  v.void() // Void type
178
269
  v.never() // Never type
270
+ v.null() // Null type
271
+ v.undefined() // Undefined type
272
+ v.nan() // NaN type
179
273
  ```
180
274
 
181
275
  ### Advanced Types
@@ -191,14 +285,19 @@ v.map(v.string(), v.number()) // Map validation
191
285
  // Objects
192
286
  v.object({ // Object schema
193
287
  name: v.string(),
194
- age: v.number()
288
+ age: v.number()
195
289
  })
290
+ v.strictObject({...}) // No extra fields allowed
291
+ v.looseObject({...}) // Extra fields passed through
196
292
 
197
293
  // Composition
198
294
  v.union(v.string(), v.number()) // Union types
199
295
  v.intersection(schemaA, schemaB) // Intersection types
296
+ v.discriminatedUnion('type', ...) // Discriminated union
297
+ v.xor(schemaA, schemaB) // Exclusive OR
200
298
  v.optional(v.string()) // Optional fields
201
299
  v.nullable(v.string()) // Nullable fields
300
+ v.nullish(v.string()) // Null or undefined
202
301
  ```
203
302
 
204
303
  ### String Validators
@@ -222,6 +321,36 @@ v.string()
222
321
  .nonempty() // Non-empty string
223
322
  ```
224
323
 
324
+ ### String Format Validators (Top-Level)
325
+
326
+ ```typescript
327
+ v.email() // Email validation
328
+ v.uuid() // UUID validation
329
+ v.uuid({ version: 'v4' }) // UUID v4 validation
330
+ v.uuidv4() // UUID v4 shortcut
331
+ v.hostname() // Hostname validation
332
+ v.emoji() // Emoji validation
333
+ v.base64() // Base64 format
334
+ v.base64url() // Base64 URL-safe format
335
+ v.hex() // Hex string
336
+ v.jwt() // JWT format
337
+ v.nanoid() // NanoID format
338
+ v.cuid() // CUID format
339
+ v.cuid2() // CUID2 format
340
+ v.ulid() // ULID format
341
+ v.ipv4() // IPv4 address
342
+ v.ipv6() // IPv6 address
343
+ v.mac() // MAC address
344
+ v.cidrv4() // IPv4 CIDR block
345
+ v.cidrv6() // IPv6 CIDR block
346
+ v.e164() // E.164 phone number
347
+ v.hash('sha256') // Hash validation
348
+ v.iso.date() // ISO date format
349
+ v.iso.time() // ISO time format
350
+ v.iso.dateTime() // ISO datetime format
351
+ v.iso.duration() // ISO duration format
352
+ ```
353
+
225
354
  ### Number Validators
226
355
 
227
356
  ```typescript
@@ -255,6 +384,7 @@ v.object({
255
384
  })
256
385
  .partial() // All fields optional
257
386
  .strict() // No extra fields
387
+ .passthrough() // Allow extra fields
258
388
  ```
259
389
 
260
390
  ### Composite Types
@@ -266,9 +396,18 @@ v.optional(v.string()) // string | undefined
266
396
  // Nullable
267
397
  v.nullable(v.string()) // string | null
268
398
 
399
+ // Nullish
400
+ v.nullish(v.string()) // string | null | undefined
401
+
269
402
  // Union
270
403
  v.union(v.string(), v.number()) // string | number
271
404
 
405
+ // Discriminated Union
406
+ v.discriminatedUnion('type',
407
+ v.object({ type: v.literal('a'), a: v.string() }),
408
+ v.object({ type: v.literal('b'), b: v.number() })
409
+ )
410
+
272
411
  // Literal
273
412
  v.literal('active') // 'active'
274
413
 
@@ -283,7 +422,7 @@ v.enum('red', 'green', 'blue') // 'red' | 'green' | 'blue'
283
422
  v.coerce.string().parse(123) // "123"
284
423
  v.coerce.string().parse(true) // "true"
285
424
 
286
- // Coerce numbers from strings/booleans
425
+ // Coerce numbers from strings/booleans
287
426
  v.coerce.number().parse("123") // 123
288
427
  v.coerce.number().parse(true) // 1
289
428
 
@@ -314,7 +453,7 @@ const userSchema = v.object({
314
453
  const publicSchema = userSchema.pick('name', 'age');
315
454
  // Type: { name: string; age: number }
316
455
 
317
- // Omit sensitive fields
456
+ // Omit sensitive fields
318
457
  const safeSchema = userSchema.omit('email', 'role');
319
458
  // Type: { name: string; age: number }
320
459
 
@@ -333,7 +472,7 @@ const extendedSchema = userSchema.extend({
333
472
  const positiveNumber = v.number()
334
473
  .refine(n => n > 0, "Number must be positive");
335
474
 
336
- // Data transformation with transform()
475
+ // Data transformation with transform()
337
476
  const uppercaseString = v.string()
338
477
  .transform(s => s.toUpperCase());
339
478
 
@@ -353,6 +492,38 @@ const complexSchema = v.string()
353
492
  .default('user@example.com');
354
493
  ```
355
494
 
495
+ ### Special Validators
496
+
497
+ ```typescript
498
+ // JSON validator with optional schema
499
+ v.json() // Any valid JSON
500
+ v.json(v.object({ name: v.string() })) // Typed JSON
501
+
502
+ // Lazy for recursive schemas
503
+ const categorySchema = v.lazy(() =>
504
+ v.object({
505
+ name: v.string(),
506
+ children: v.array(categorySchema).optional()
507
+ })
508
+ );
509
+
510
+ // Custom validator
511
+ v.custom({
512
+ check: (val) => typeof val === 'string' && val.length > 0,
513
+ message: 'Must be a non-empty string'
514
+ });
515
+
516
+ // File validator
517
+ v.file()
518
+ .maxSize(5 * 1024 * 1024) // 5MB
519
+ .type(['image/png', 'image/jpeg']);
520
+
521
+ // Function validator
522
+ v.function()
523
+ .args(v.string(), v.number())
524
+ .returns(v.boolean());
525
+ ```
526
+
356
527
  ### Type Inference
357
528
 
358
529
  ```typescript
@@ -371,7 +542,7 @@ type User = Infer<typeof schema>;
371
542
  ### Error Formatting Types
372
543
 
373
544
  ```typescript
374
- import {
545
+ import {
375
546
  VldError, // Main error class
376
547
  VldIssue, // Individual validation issue
377
548
  VldErrorTree, // Nested error structure
@@ -390,7 +561,7 @@ if (!result.success) {
390
561
  }
391
562
  ```
392
563
 
393
- ## 🌍 Internationalization (i18n)
564
+ ## Internationalization (i18n)
394
565
 
395
566
  VLD supports 27+ languages out of the box with comprehensive error messages:
396
567
 
@@ -403,7 +574,7 @@ schema.safeParse('Hi'); // Error: "String must be at least 5 characters"
403
574
 
404
575
  // Switch to Turkish
405
576
  setLocale('tr');
406
- schema.safeParse('Hi'); // Error: "Metin en az 5 karakter olmalı"
577
+ schema.safeParse('Hi'); // Error: "Metin en az 5 karakter olmali"
407
578
 
408
579
  // Switch to Spanish
409
580
  setLocale('es');
@@ -411,42 +582,39 @@ schema.safeParse('Hi'); // Error: "La cadena debe tener al menos 5 caracteres"
411
582
 
412
583
  // Switch to Japanese
413
584
  setLocale('ja');
414
- schema.safeParse('Hi'); // Error: "文字列は5文字以上である必要があります"
585
+ schema.safeParse('Hi'); // Error: "..."
415
586
  ```
416
587
 
417
588
  ### Supported Languages
418
589
 
419
590
  #### Base Languages (15):
420
- - 🇬🇧 English (`en`) - 🇹🇷 Turkish (`tr`) - 🇪🇸 Spanish (`es`) - 🇫🇷 French (`fr`) - 🇩🇪 German (`de`)
421
- - 🇮🇹 Italian (`it`) - 🇵🇹 Portuguese (`pt`) - 🇷🇺 Russian (`ru`) - 🇯🇵 Japanese (`ja`) - 🇰🇷 Korean (`ko`)
422
- - 🇨🇳 Chinese (`zh`) - 🇸🇦 Arabic (`ar`) - 🇮🇳 Hindi (`hi`) - 🇳🇱 Dutch (`nl`) - 🇵🇱 Polish (`pl`)
591
+ - English (`en`) - Turkish (`tr`) - Spanish (`es`) - French (`fr`) - German (`de`)
592
+ - Italian (`it`) - Portuguese (`pt`) - Russian (`ru`) - Japanese (`ja`) - Korean (`ko`)
593
+ - Chinese (`zh`) - Arabic (`ar`) - Hindi (`hi`) - Dutch (`nl`) - Polish (`pl`)
423
594
 
424
595
  #### European Languages (4):
425
- - 🇩🇰 Danish (`da`) - 🇸🇪 Swedish (`sv`) - 🇳🇴 Norwegian (`no`) - 🇫🇮 Finnish (`fi`)
596
+ - Danish (`da`) - Swedish (`sv`) - Norwegian (`no`) - Finnish (`fi`)
426
597
 
427
598
  #### Asian Languages (4):
428
- - 🇹🇭 Thai (`th`) - 🇻🇳 Vietnamese (`vi`) - 🇮🇩 Indonesian (`id`) - 🇧🇩 Bengali (`bn`)
599
+ - Thai (`th`) - Vietnamese (`vi`) - Indonesian (`id`) - Bengali (`bn`)
429
600
 
430
601
  #### African Languages (2):
431
- - 🇰🇪 Swahili (`sw`) - 🇿🇦 Afrikaans (`af`)
602
+ - Swahili (`sw`) - Afrikaans (`af`)
432
603
 
433
604
  #### American Languages (2):
434
- - 🇧🇷 Portuguese Brazil (`pt-BR`) - 🇲🇽 Spanish Mexico (`es-MX`)
605
+ - Portuguese Brazil (`pt-BR`) - Spanish Mexico (`es-MX`)
435
606
 
436
- **Plus 75+ additional languages** supported through comprehensive type definitions with English fallback, including Icelandic, Czech, Slovak, Hungarian, Romanian, Bulgarian, Croatian, Slovenian, Greek, Hebrew, Persian, Georgian, Armenian, and many more!
607
+ **Plus 75+ additional languages** supported through comprehensive type definitions with English fallback.
437
608
 
438
- ## ⚠️ Error Handling & Formatting
609
+ ## Error Handling & Formatting
439
610
 
440
- VLD provides advanced error formatting utilities similar to Zod's error handling system. These utilities help you transform validation errors into user-friendly formats for different use cases.
611
+ VLD provides advanced error formatting utilities similar to Zod's error handling system.
441
612
 
442
613
  ### Error Formatting Utilities
443
614
 
444
615
  ```typescript
445
616
  import { v, VldError, treeifyError, prettifyError, flattenError } from '@oxog/vld';
446
617
 
447
- // Note: Error formatting utilities like `treeifyError` are separate named exports
448
- // and are not part of the main `v` object.
449
-
450
618
  const userSchema = v.object({
451
619
  username: v.string().min(3),
452
620
  favoriteNumbers: v.array(v.number()),
@@ -456,10 +624,9 @@ const userSchema = v.object({
456
624
  })
457
625
  });
458
626
 
459
- // This will fail validation
460
627
  const result = userSchema.safeParse({
461
- username: 'ab', // too short
462
- favoriteNumbers: [1, 'two', 3], // 'two' is not a number
628
+ username: 'ab',
629
+ favoriteNumbers: [1, 'two', 3],
463
630
  profile: {
464
631
  name: '',
465
632
  email: 'invalid-email'
@@ -469,60 +636,15 @@ const result = userSchema.safeParse({
469
636
 
470
637
  if (!result.success) {
471
638
  const error = result.error as VldError;
472
-
639
+
473
640
  // 1. Tree Format - Nested structure for complex UIs
474
641
  const tree = treeifyError(error);
475
- console.log(tree);
476
- /*
477
- {
478
- errors: ['Unrecognized key: "extraField"'],
479
- properties: {
480
- username: { errors: ['String must be at least 3 characters'] },
481
- favoriteNumbers: {
482
- items: [
483
- undefined,
484
- { errors: ['Expected number, received string'] },
485
- undefined
486
- ]
487
- },
488
- profile: {
489
- properties: {
490
- name: { errors: ['String cannot be empty'] },
491
- email: { errors: ['Invalid email format'] }
492
- }
493
- }
494
- }
495
- }
496
- */
497
-
642
+
498
643
  // 2. Pretty Format - Human-readable console output
499
644
  const pretty = prettifyError(error);
500
- console.log(pretty);
501
- /*
502
- ✖ Unrecognized key: "extraField"
503
- ✖ String must be at least 3 characters
504
- → at username
505
- ✖ Expected number, received string
506
- → at favoriteNumbers[1]
507
- ✖ String cannot be empty
508
- → at profile.name
509
- ✖ Invalid email format
510
- → at profile.email
511
- */
512
-
645
+
513
646
  // 3. Flatten Format - Simple form validation
514
647
  const flattened = flattenError(error);
515
- console.log(flattened);
516
- /*
517
- {
518
- formErrors: ['Unrecognized key: "extraField"'],
519
- fieldErrors: {
520
- username: ['String must be at least 3 characters'],
521
- favoriteNumbers: ['Expected number, received string'],
522
- profile: ['String cannot be empty', 'Invalid email format']
523
- }
524
- }
525
- */
526
648
  }
527
649
  ```
528
650
 
@@ -532,24 +654,23 @@ if (!result.success) {
532
654
  ```typescript
533
655
  function UserForm() {
534
656
  const [errors, setErrors] = useState<VldFlattenedError | null>(null);
535
-
657
+
536
658
  const handleSubmit = (data: unknown) => {
537
659
  const result = userSchema.safeParse(data);
538
-
660
+
539
661
  if (!result.success) {
540
662
  setErrors(flattenError(result.error as VldError));
541
663
  } else {
542
664
  setErrors(null);
543
- // Process valid data
544
665
  }
545
666
  };
546
-
667
+
547
668
  return (
548
669
  <form onSubmit={handleSubmit}>
549
670
  {errors?.formErrors.map(error => (
550
671
  <div key={error} className="form-error">{error}</div>
551
672
  ))}
552
-
673
+
553
674
  <input name="username" />
554
675
  {errors?.fieldErrors.username?.map(error => (
555
676
  <div key={error} className="field-error">{error}</div>
@@ -563,32 +684,18 @@ function UserForm() {
563
684
  ```typescript
564
685
  app.post('/api/users', (req, res) => {
565
686
  const result = userSchema.safeParse(req.body);
566
-
687
+
567
688
  if (!result.success) {
568
689
  const tree = treeifyError(result.error as VldError);
569
690
  res.status(400).json({
570
691
  error: 'Validation failed',
571
692
  details: tree
572
693
  });
573
- } else {
574
- // Process valid user data
575
694
  }
576
695
  });
577
696
  ```
578
697
 
579
- #### Console Debugging
580
- ```typescript
581
- function validateAndLog(data: unknown) {
582
- const result = userSchema.safeParse(data);
583
-
584
- if (!result.success) {
585
- console.log('Validation failed:');
586
- console.log(prettifyError(result.error as VldError));
587
- }
588
- }
589
- ```
590
-
591
- ## 🔥 Advanced Examples
698
+ ## Advanced Examples
592
699
 
593
700
  ### Complex Validation with New Features
594
701
 
@@ -600,11 +707,11 @@ const postSchema = v.object({
600
707
  author: v.object({
601
708
  name: v.string(),
602
709
  email: v.string().email(),
603
- age: v.coerce.number(), // Auto-convert to number
710
+ age: v.coerce.number(),
604
711
  }),
605
- tags: v.set(v.string()).default(new Set()), // Use Set instead of array
606
- metadata: v.record(v.any()), // Key-value metadata
607
- coordinates: v.tuple(v.number(), v.number()), // [lat, lng]
712
+ tags: v.set(v.string()).default(new Set()),
713
+ metadata: v.record(v.any()),
714
+ coordinates: v.tuple(v.number(), v.number()),
608
715
  publishedAt: v.date().default(() => new Date()),
609
716
  status: v.enum('draft', 'published', 'archived')
610
717
  });
@@ -615,125 +722,60 @@ const blogPostSchema = postSchema.extend({
615
722
  categories: v.array(v.string()).min(1),
616
723
  featured: v.boolean().default(false)
617
724
  });
618
-
619
- // Create a public version without sensitive data
620
- const publicPostSchema = blogPostSchema
621
- .omit('author')
622
- .extend({
623
- authorName: v.string()
624
- });
625
725
  ```
626
726
 
627
- ### Advanced Transformations & Validation
727
+ ### Discriminated Union
628
728
 
629
729
  ```typescript
630
- // Complex email processing with coercion and transformation
631
- const emailSchema = v.coerce.string()
632
- .transform(s => s.toLowerCase().trim())
633
- .refine(s => s.includes('@'), 'Must be valid email format')
634
- .transform(s => s.replace(/\+.*@/, '@')) // Remove plus addressing
635
- .catch('invalid@example.com');
636
-
637
- // Process user input with fallbacks
638
- const userInputSchema = v.object({
639
- name: v.coerce.string()
640
- .transform(s => s.trim())
641
- .refine(s => s.length > 0, 'Name cannot be empty')
642
- .default('Anonymous'),
643
-
644
- age: v.coerce.number()
645
- .refine(n => n >= 0 && n <= 150, 'Age must be realistic')
646
- .catch(0),
647
-
648
- preferences: v.record(v.any()).default({}),
649
-
650
- tags: v.union(
651
- v.array(v.string()),
652
- v.coerce.string().transform(s => s.split(','))
653
- ).default([])
654
- });
655
-
656
- // Intersection for combining user types
657
- const baseUser = v.object({
658
- id: v.string(),
659
- name: v.string()
660
- });
730
+ const eventSchema = v.discriminatedUnion('type',
731
+ v.object({
732
+ type: v.literal('click'),
733
+ x: v.number(),
734
+ y: v.number()
735
+ }),
736
+ v.object({
737
+ type: v.literal('scroll'),
738
+ direction: v.enum('up', 'down'),
739
+ distance: v.number()
740
+ }),
741
+ v.object({
742
+ type: v.literal('keypress'),
743
+ key: v.string(),
744
+ modifiers: v.array(v.enum('ctrl', 'alt', 'shift'))
745
+ })
746
+ );
661
747
 
662
- const adminUser = v.object({
663
- role: v.literal('admin'),
664
- permissions: v.array(v.string())
748
+ // Type-safe parsing
749
+ const event = eventSchema.parse({
750
+ type: 'click',
751
+ x: 100,
752
+ y: 200
665
753
  });
666
-
667
- const adminSchema = v.intersection(baseUser, adminUser);
668
754
  ```
669
755
 
670
- ### Collection Validation
756
+ ### Recursive Schemas
671
757
 
672
758
  ```typescript
673
- // Advanced tuple validation
674
- const coordinatesSchema = v.tuple(
675
- v.number().min(-90).max(90), // latitude
676
- v.number().min(-180).max(180), // longitude
677
- v.number().positive().optional() // altitude
678
- );
679
-
680
- // Map validation for configuration
681
- const configSchema = v.map(
682
- v.string().min(1), // keys must be non-empty strings
683
- v.union(v.string(), v.number(), v.boolean()) // values can be mixed types
759
+ const categorySchema: ReturnType<typeof v.lazy> = v.lazy(() =>
760
+ v.object({
761
+ name: v.string(),
762
+ slug: v.string().regex(/^[a-z0-9-]+$/),
763
+ children: v.array(categorySchema).optional()
764
+ })
684
765
  );
685
766
 
686
- // Set validation for unique tags
687
- const uniqueTagsSchema = v.set(v.string().min(1).max(20))
688
- .refine(tags => tags.size <= 10, 'Too many tags');
689
- ```
690
-
691
- ### Real-world API Schema
692
-
693
- ```typescript
694
- // Complete API endpoint schema with all features
695
- const apiUserSchema = v.object({
696
- // Basic info with coercion
697
- id: v.coerce.string(),
698
- username: v.string()
699
- .min(3)
700
- .max(20)
701
- .refine(s => /^[a-zA-Z0-9_]+$/.test(s), 'Invalid username format'),
702
-
703
- email: v.coerce.string()
704
- .transform(s => s.toLowerCase().trim())
705
- .refine(s => s.includes('@'), 'Invalid email'),
706
-
707
- // Age with fallback
708
- age: v.coerce.number()
709
- .min(13)
710
- .max(120)
711
- .catch(null),
712
-
713
- // Preferences as key-value store
714
- preferences: v.record(v.any()).default({}),
715
-
716
- // Roles as a set for uniqueness
717
- roles: v.set(v.enum('user', 'admin', 'moderator'))
718
- .default(new Set(['user'])),
719
-
720
- // Metadata with BigInt support
721
- createdAt: v.coerce.date(),
722
- userId: v.coerce.bigint(),
723
-
724
- // Optional complex nested data
725
- profile: v.object({
726
- bio: v.string().max(500).default(''),
727
- location: v.tuple(v.number(), v.number()).optional(),
728
- socialLinks: v.record(v.string().url()).default({})
729
- }).optional()
730
- });
731
-
732
- // Specialized schemas using pick/omit
733
- const publicUserSchema = apiUserSchema.pick('username', 'profile');
734
- const adminUserSchema = apiUserSchema.extend({
735
- adminNotes: v.string().optional(),
736
- lastLogin: v.date().optional()
767
+ const category = categorySchema.parse({
768
+ name: 'Electronics',
769
+ slug: 'electronics',
770
+ children: [
771
+ {
772
+ name: 'Phones',
773
+ slug: 'phones',
774
+ children: [
775
+ { name: 'Smartphones', slug: 'smartphones' }
776
+ ]
777
+ }
778
+ ]
737
779
  });
738
780
  ```
739
781
 
@@ -750,318 +792,323 @@ type LoginForm = Infer<typeof loginSchema>;
750
792
 
751
793
  function handleLogin(data: unknown) {
752
794
  const result = loginSchema.safeParse(data);
753
-
795
+
754
796
  if (result.success) {
755
- // data is now typed as LoginForm
756
797
  const { username, password, rememberMe } = result.data;
757
798
  // ... handle login
758
- } else {
759
- // Handle validation errors
760
- console.error(result.error);
761
799
  }
762
800
  }
763
801
  ```
764
802
 
765
- ## 🆚 VLD vs. Zod
803
+ ## Codecs - Bidirectional Transformations
766
804
 
767
- VLD is designed as a compelling alternative to Zod, offering full feature parity while delivering significant improvements in performance, bundle size, and internationalization.
805
+ VLD introduces **codecs** - powerful bidirectional transformations that can convert data between different representations.
768
806
 
769
- ### Feature Comparison
807
+ ### What are Codecs?
770
808
 
771
- | Feature | VLD | Zod |
772
- | ----------------------- | ---------------------------------- | ------------------------------------ |
773
- | **Performance** | **~2.07x faster** (average) | Baseline |
774
- | **Memory Usage** | **~78% less** overall | Baseline |
775
- | **Internationalization**| ✅ **Built-in (27+ languages)** | ❌ Requires third-party library |
776
- | **Dependencies** | **Zero** | `zod-i18n` for locales |
777
- | **Bundle Size** | Smaller | Larger |
778
- | **API** | 100% Zod-compatible | Standard Zod API |
779
- | **Codecs** | ✅ Built-in, bidirectional | ✅ Via external `zod-codecs` |
780
- | **Error Formatting** | ✅ Advanced (tree, pretty, flatten)| ✅ Advanced (tree, pretty, flatten)|
781
- | **Type Inference** | ✅ Excellent | ✅ Excellent |
809
+ Codecs enable safe, type-checked conversions between different data formats:
782
810
 
783
- ### 🔄 Seamless Migration from Zod
811
+ ```typescript
812
+ import { stringToNumber, jsonCodec, base64ToBytes } from '@oxog/vld';
784
813
 
785
- Migration is straightforward due to 100% API compatibility. You can typically just swap the import statement.
814
+ // String to number conversion
815
+ const age = stringToNumber.parse('25'); // 25
816
+ const price = stringToNumber.encode(99.99); // "99.99"
786
817
 
787
- ```javascript
788
- // Before (Zod)
789
- import { z } from 'zod';
790
- const schema = z.string().email();
818
+ // JSON codec
819
+ const userJson = jsonCodec();
820
+ const user = userJson.parse('{"name":"John","age":30}');
821
+ const jsonString = userJson.encode(user);
791
822
 
792
- // After (VLD) - Exact same syntax!
793
- import { v } from '@oxog/vld';
794
- const schema = v.string().email();
823
+ // Binary data
824
+ const bytes = base64ToBytes.parse('SGVsbG8gV29ybGQ=');
795
825
  ```
796
826
 
797
- ## 🔄 Codecs - Bidirectional Transformations
827
+ ### Built-in Codecs
798
828
 
799
- VLD introduces **codecs** - powerful bidirectional transformations that can convert data between different representations. Unlike simple transformations, codecs can both **decode** (input → output) and **encode** (output → input).
829
+ #### String Conversion Codecs
830
+ ```typescript
831
+ import { stringToNumber, stringToInt, stringToBigInt, stringToBoolean } from '@oxog/vld';
800
832
 
801
- ### 🎯 What are Codecs?
833
+ stringToNumber.parse('42.5'); // 42.5
834
+ stringToInt.parse('42'); // 42
835
+ stringToBigInt.parse('123n'); // 123n
836
+ stringToBoolean.parse('true'); // true
837
+ ```
802
838
 
803
- Codecs enable safe, type-checked conversions between different data formats. They're perfect for:
804
- - **API boundaries**: Convert strings to structured data
805
- - **Database serialization**: Transform objects to/from storage formats
806
- - **Network protocols**: Handle data encoding/decoding
807
- - **Configuration parsing**: Convert config strings to typed values
839
+ #### Date Conversion Codecs
840
+ ```typescript
841
+ import { isoDatetimeToDate, epochSecondsToDate, epochMillisToDate } from '@oxog/vld';
808
842
 
809
- ### 📦 Built-in Codecs
843
+ isoDatetimeToDate.parse('2023-12-25T10:30:00.000Z'); // Date
844
+ epochSecondsToDate.parse(1703505000); // Date
845
+ epochMillisToDate.parse(1703505000000); // Date
846
+ ```
810
847
 
811
- VLD provides all Zod-compatible codecs plus additional utilities:
848
+ #### URL Codecs
849
+ ```typescript
850
+ import { stringToURL, stringToHttpURL, uriComponent } from '@oxog/vld';
812
851
 
813
- #### **String Conversion Codecs**
852
+ stringToURL.parse('https://example.com/path?q=1');
853
+ stringToHttpURL.parse('https://api.example.com');
854
+ uriComponent.parse('Hello World!'); // "Hello%20World!"
855
+ ```
814
856
 
857
+ #### Binary Data Codecs
815
858
  ```typescript
816
- import { stringToNumber, stringToInt, stringToBigInt, stringToBoolean } from '@oxog/vld';
859
+ import { base64ToBytes, hexToBytes, utf8ToBytes, bytesToUtf8 } from '@oxog/vld';
817
860
 
818
- // String to number conversion
819
- const age = stringToNumber.parse('25'); // 25
820
- const price = stringToNumber.encode(99.99); // "99.99"
861
+ base64ToBytes.parse('SGVsbG8='); // Uint8Array
862
+ hexToBytes.parse('48656c6c6f'); // Uint8Array
863
+ utf8ToBytes.parse('Hello'); // Uint8Array
864
+ bytesToUtf8.parse(new Uint8Array([72, 101, 108, 108, 111])); // "Hello"
865
+ ```
821
866
 
822
- // String to integer (validates integer constraint)
823
- const count = stringToInt.parse('42'); // 42
824
- stringToInt.parse('42.5'); // ❌ Validation error: must be integer
867
+ ### Custom Codecs
825
868
 
826
- // String to BigInt for large numbers
827
- const bigNum = stringToBigInt.parse('123456789012345678901234567890'); // 123456789012345678901234567890n
869
+ ```typescript
870
+ const csvToArray = v.codec(
871
+ v.string(),
872
+ v.array(v.string()),
873
+ {
874
+ decode: (csv: string) => csv.split(',').map(s => s.trim()),
875
+ encode: (arr: string[]) => arr.join(', ')
876
+ }
877
+ );
828
878
 
829
- // String to boolean (flexible parsing)
830
- stringToBoolean.parse('true'); // true
831
- stringToBoolean.parse('1'); // true
832
- stringToBoolean.parse('yes'); // true
833
- stringToBoolean.parse('on'); // true
834
- stringToBoolean.parse('false'); // false
835
- stringToBoolean.parse('0'); // false
879
+ const tags = csvToArray.parse('react, typescript, vld');
880
+ // ["react", "typescript", "vld"]
881
+
882
+ const csvString = csvToArray.encode(['node', 'express', 'api']);
883
+ // "node, express, api"
836
884
  ```
837
885
 
838
- #### **Date Conversion Codecs**
886
+ ## Plugin System
887
+
888
+ VLD v1.5.0 introduces a powerful plugin system for extending functionality.
889
+
890
+ ### Creating a Plugin
839
891
 
840
892
  ```typescript
841
- import { isoDatetimeToDate, epochSecondsToDate, epochMillisToDate } from '@oxog/vld';
893
+ import { definePlugin, usePlugin, v } from '@oxog/vld';
894
+
895
+ // Define a custom plugin
896
+ const myPlugin = definePlugin({
897
+ name: 'my-plugin',
898
+ version: '1.0.0',
842
899
 
843
- // ISO datetime string to Date
844
- const date1 = isoDatetimeToDate.parse('2023-12-25T10:30:00.000Z');
845
- console.log(date1.toISOString()); // "2023-12-25T10:30:00.000Z"
900
+ // Custom validators
901
+ validators: {
902
+ phoneNumber: () => v.string().regex(/^\+?[1-9]\d{1,14}$/),
903
+ postalCode: () => v.string().regex(/^\d{5}(-\d{4})?$/)
904
+ },
846
905
 
847
- // Unix epoch seconds to Date
848
- const date2 = epochSecondsToDate.parse(1703505000);
849
- console.log(date2.getFullYear()); // 2023
906
+ // Custom transforms
907
+ transforms: {
908
+ normalizePhone: (phone: string) => phone.replace(/[^\d+]/g, '')
909
+ },
850
910
 
851
- // Unix epoch milliseconds to Date
852
- const date3 = epochMillisToDate.parse(1703505000000);
853
- console.log(date3.getMonth()); // 11 (December)
911
+ // Lifecycle hooks
912
+ install(kernel) {
913
+ console.log('Plugin installed!');
914
+ }
915
+ });
854
916
 
855
- // All support bidirectional conversion
856
- const backToEpoch = epochSecondsToDate.encode(new Date()); // Unix timestamp
917
+ // Register the plugin
918
+ usePlugin(myPlugin);
857
919
  ```
858
920
 
859
- #### **JSON and Complex Data Codecs**
921
+ ### Using Plugin Validators
860
922
 
861
923
  ```typescript
862
- import { jsonCodec, base64Json } from '@oxog/vld';
924
+ import { createVldKernel, usePlugin } from '@oxog/vld';
863
925
 
864
- // Generic JSON codec
865
- const userJson = jsonCodec();
866
- const user = userJson.parse('{"name":"John","age":30}'); // { name: "John", age: 30 }
867
- const jsonString = userJson.encode(user); // '{"name":"John","age":30}'
926
+ const kernel = createVldKernel({ debug: true });
868
927
 
869
- // JSON codec with schema validation
870
- const userSchema = v.object({
871
- name: v.string(),
872
- age: v.number()
873
- });
874
- const typedJsonCodec = jsonCodec(userSchema);
875
- const validatedUser = typedJsonCodec.parse('{"name":"John","age":30}'); // Fully typed!
928
+ kernel.use(myPlugin);
876
929
 
877
- // Base64-encoded JSON
878
- const b64JsonCodec = base64Json(userSchema);
879
- const encoded = b64JsonCodec.encode({ name: "Alice", age: 25 }); // Base64 string
880
- const decoded = b64JsonCodec.parse(encoded); // { name: "Alice", age: 25 }
930
+ // Access custom validators
931
+ const phoneSchema = kernel.validator('phoneNumber');
932
+ phoneSchema.parse('+1234567890');
881
933
  ```
882
934
 
883
- #### **URL and Web Codecs**
935
+ ## Result Pattern
936
+
937
+ VLD v1.5.0 includes a functional Result pattern for error handling.
938
+
939
+ ### Basic Usage
884
940
 
885
941
  ```typescript
886
- import { stringToURL, stringToHttpURL, uriComponent } from '@oxog/vld';
942
+ import { Ok, Err, match, map, flatMap, tryCatch } from '@oxog/vld';
943
+
944
+ // Create results
945
+ const success = Ok(42);
946
+ const failure = Err(new Error('Something went wrong'));
947
+
948
+ // Pattern matching
949
+ const message = match(success, {
950
+ ok: (value) => `Got: ${value}`,
951
+ err: (error) => `Error: ${error.message}`
952
+ });
887
953
 
888
- // String to URL object
889
- const url = stringToURL.parse('https://example.com/path?param=value');
890
- console.log(url.hostname); // "example.com"
891
- console.log(url.searchParams.get('param')); // "value"
954
+ // Transform results
955
+ const doubled = map(success, (n) => n * 2); // Ok(84)
892
956
 
893
- // Restrict to HTTP/HTTPS only
894
- const httpUrl = stringToHttpURL.parse('https://api.example.com');
895
- stringToHttpURL.parse('ftp://files.example.com'); // Error: Must be HTTP/HTTPS
957
+ // Chain operations
958
+ const result = flatMap(success, (n) =>
959
+ n > 0 ? Ok(n * 2) : Err(new Error('Must be positive'))
960
+ );
896
961
 
897
- // URI component encoding/decoding
898
- const encoded = uriComponent.parse('Hello World! 🚀'); // "Hello%20World!%20%F0%9F%9A%80"
899
- const decoded = uriComponent.encode(encoded); // "Hello World! 🚀"
962
+ // Safe function execution
963
+ const parsed = tryCatch(() => JSON.parse('{"a":1}'));
900
964
  ```
901
965
 
902
- #### **Binary Data Codecs**
966
+ ### With Validation
903
967
 
904
968
  ```typescript
905
- import { base64ToBytes, hexToBytes, utf8ToBytes, bytesToUtf8 } from '@oxog/vld';
969
+ import { v, isOk, isErr, unwrapOr } from '@oxog/vld';
906
970
 
907
- // Base64 to byte array
908
- const bytes1 = base64ToBytes.parse('SGVsbG8gV29ybGQ='); // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
971
+ const schema = v.object({
972
+ name: v.string(),
973
+ age: v.number().min(0)
974
+ });
975
+
976
+ const result = schema.safeParse(data);
977
+
978
+ if (isOk(result)) {
979
+ console.log('Valid:', result.data);
980
+ } else {
981
+ console.log('Invalid:', result.error);
982
+ }
983
+
984
+ // With default value
985
+ const user = unwrapOr(result, { name: 'Guest', age: 0 });
986
+ ```
909
987
 
910
- // Hex to byte array
911
- const bytes2 = hexToBytes.parse('48656c6c6f'); // Uint8Array([72, 101, 108, 108, 111])
988
+ ### Combining Results
912
989
 
913
- // UTF-8 string to bytes
914
- const bytes3 = utf8ToBytes.parse('Hello! 👋'); // Uint8Array([...])
990
+ ```typescript
991
+ import { all, fromNullable } from '@oxog/vld';
915
992
 
916
- // Bytes to UTF-8 string
917
- const text = bytesToUtf8.parse(bytes3); // "Hello! 👋"
993
+ // Combine multiple results
994
+ const results = [Ok(1), Ok(2), Ok(3)];
995
+ const combined = all(results); // Ok([1, 2, 3])
918
996
 
919
- // All support round-trip conversion
920
- const original = 'Hello World!';
921
- const roundTrip = bytesToUtf8.parse(utf8ToBytes.parse(original)); // "Hello World!"
997
+ // Convert nullable to Result
998
+ const maybeValue: string | null = getValue();
999
+ const result = fromNullable(maybeValue, new Error('Value is null'));
922
1000
  ```
923
1001
 
924
- ### 🛠 Custom Codecs
1002
+ ## CLI Tools
925
1003
 
926
- Create your own codecs for specific use cases:
1004
+ VLD includes command-line tools for validation and benchmarking.
927
1005
 
928
- ```typescript
929
- import { v } from '@oxog/vld';
1006
+ ### Installation
930
1007
 
931
- // Custom CSV to array codec
932
- const csvToArray = v.codec(
933
- v.string(), // Input: CSV string
934
- v.array(v.string()), // Output: Array of strings
935
- {
936
- decode: (csv: string) => csv.split(',').map(s => s.trim()),
937
- encode: (arr: string[]) => arr.join(', ')
938
- }
939
- );
1008
+ ```bash
1009
+ npm install -g @oxog/vld
1010
+ # or use npx
1011
+ npx vld --help
1012
+ ```
940
1013
 
941
- const tags = csvToArray.parse('react, typescript, vld'); // ["react", "typescript", "vld"]
942
- const csvString = csvToArray.encode(['node', 'express', 'api']); // "node, express, api"
1014
+ ### Commands
943
1015
 
944
- // Complex: Environment config codec
945
- const envConfigCodec = v.codec(
946
- v.string(),
947
- v.object({
948
- port: v.number(),
949
- debug: v.boolean(),
950
- dbUrl: v.string()
951
- }),
952
- {
953
- decode: (envString: string) => {
954
- const config = {};
955
- envString.split('\n').forEach(line => {
956
- const [key, value] = line.split('=');
957
- if (key === 'PORT') config.port = parseInt(value, 10);
958
- if (key === 'DEBUG') config.debug = value === 'true';
959
- if (key === 'DB_URL') config.dbUrl = value;
960
- });
961
- return config;
962
- },
963
- encode: (config) => [
964
- `PORT=${config.port}`,
965
- `DEBUG=${config.debug}`,
966
- `DB_URL=${config.dbUrl}`
967
- ].join('\n')
968
- }
969
- );
1016
+ ```bash
1017
+ # Show help
1018
+ vld --help
1019
+
1020
+ # Validate data
1021
+ vld validate schema.json data.json
1022
+
1023
+ # Run benchmarks
1024
+ vld benchmark
1025
+
1026
+ # Show version
1027
+ vld --version
970
1028
  ```
971
1029
 
972
- ### 🚀 Advanced Codec Features
1030
+ ### Programmatic CLI
973
1031
 
974
- #### **Async Codecs**
975
1032
  ```typescript
976
- const asyncCodec = v.codec(
977
- v.string(),
978
- v.object({ data: v.string() }),
979
- {
980
- decode: async (str: string) => {
981
- // Simulate API call
982
- const response = await fetch(`/api/decode?data=${str}`);
983
- return response.json();
984
- },
985
- encode: async (obj) => {
986
- const response = await fetch('/api/encode', {
987
- method: 'POST',
988
- body: JSON.stringify(obj)
989
- });
990
- return response.text();
1033
+ import { createCli, vldCli } from '@oxog/vld/cli';
1034
+
1035
+ // Use the built-in CLI
1036
+ vldCli.run(process.argv.slice(2));
1037
+
1038
+ // Or create a custom CLI
1039
+ const cli = createCli('my-app', '1.0.0', 'My validation app')
1040
+ .command({
1041
+ name: 'validate',
1042
+ description: 'Validate data',
1043
+ action: async (args, options) => {
1044
+ // Custom validation logic
991
1045
  }
992
- }
993
- );
1046
+ });
994
1047
 
995
- // Use async methods
996
- const result = await asyncCodec.parseAsync('input-data');
997
- const encoded = await asyncCodec.encodeAsync({ data: 'output' });
1048
+ cli.run(process.argv.slice(2));
998
1049
  ```
999
1050
 
1000
- #### **Error Handling**
1001
- ```typescript
1002
- const safeParseResult = stringToNumber.safeParse('not-a-number');
1003
- if (!safeParseResult.success) {
1004
- console.error('Parse failed:', safeParseResult.error.message);
1005
- }
1051
+ ## Logger & Colored Output
1006
1052
 
1007
- const safeEncodeResult = stringToNumber.safeEncode('invalid-input');
1008
- if (!safeEncodeResult.success) {
1009
- console.error('Encode failed:', safeEncodeResult.error.message);
1010
- }
1011
- ```
1053
+ VLD includes a logging system and colored terminal output.
1054
+
1055
+ ### Logger
1012
1056
 
1013
- #### **JWT Payload Decoder**
1014
1057
  ```typescript
1015
- import { jwtPayload } from '@oxog/vld';
1058
+ import { createLogger, setLogLevel, enableDebug } from '@oxog/vld';
1016
1059
 
1017
- // Decode JWT payload (read-only)
1018
- const payloadSchema = v.object({
1019
- sub: v.string(),
1020
- name: v.string(),
1021
- iat: v.number()
1022
- });
1060
+ // Create a logger
1061
+ const logger = createLogger({ prefix: 'VLD' });
1023
1062
 
1024
- const decoder = jwtPayload(payloadSchema);
1025
- const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
1063
+ logger.info('Processing...');
1064
+ logger.warn('Deprecated feature');
1065
+ logger.error('Validation failed');
1066
+ logger.debug('Debug info');
1026
1067
 
1027
- const payload = decoder.parse(token);
1028
- console.log(payload.name); // "John Doe"
1029
- console.log(payload.sub); // "1234567890"
1030
- ```
1068
+ // Set log level globally
1069
+ setLogLevel('debug');
1031
1070
 
1032
- ### 🎯 Codec vs Transform
1071
+ // Enable debug mode
1072
+ enableDebug();
1073
+ ```
1033
1074
 
1034
- | Feature | Codec | Transform |
1035
- |---------|--------|-----------|
1036
- | **Direction** | Bidirectional (encode/decode) | Unidirectional (transform only) |
1037
- | **Type Safety** | Input and output validation | Output validation only |
1038
- | **Use Case** | Data serialization, API boundaries | Data cleaning, formatting |
1039
- | **Performance** | Optimized for round-trips | Optimized for single direction |
1075
+ ### Colored Output (Pigment)
1040
1076
 
1041
1077
  ```typescript
1042
- // Transform: One-way conversion
1043
- const upperCase = v.string().transform(s => s.toUpperCase());
1044
- const result = upperCase.parse('hello'); // "HELLO"
1045
- // No way to get back to "hello"
1078
+ import { pigment, red, green, blue, bold, dim } from '@oxog/vld';
1046
1079
 
1047
- // Codec: Two-way conversion
1048
- const upperCaseCodec = v.codec(
1049
- v.string(),
1050
- v.string(),
1051
- {
1052
- decode: s => s.toUpperCase(),
1053
- encode: s => s.toLowerCase()
1054
- }
1055
- );
1056
- const encoded = upperCaseCodec.parse('hello'); // "HELLO"
1057
- const original = upperCaseCodec.encode('HELLO'); // "hello"
1080
+ console.log(red('Error!'));
1081
+ console.log(green('Success!'));
1082
+ console.log(bold(blue('Important')));
1083
+ console.log(dim('Less important'));
1084
+
1085
+ // Or use the pigment object
1086
+ console.log(pigment.red('Error!'));
1087
+ console.log(pigment.bold(pigment.green('Success!')));
1058
1088
  ```
1059
1089
 
1060
- ## 🔄 Migrating from Zod
1090
+ ## VLD vs. Zod
1061
1091
 
1062
- VLD provides 100% feature parity with Zod, making migration seamless:
1092
+ VLD is designed as a compelling alternative to Zod, offering full feature parity while delivering significant improvements.
1093
+
1094
+ ### Feature Comparison
1095
+
1096
+ | Feature | VLD | Zod |
1097
+ | ----------------------- | ---------------------------------- | ------------------------------------ |
1098
+ | **Performance** | **~1.98x faster** (average) | Baseline |
1099
+ | **Memory Usage** | **~78% less** overall | Baseline |
1100
+ | **Internationalization**| **Built-in (27+ languages)** | Requires third-party library |
1101
+ | **Dependencies** | **Zero** | `zod-i18n` for locales |
1102
+ | **Bundle Size** | Smaller | Larger |
1103
+ | **API** | 100% Zod-compatible | Standard Zod API |
1104
+ | **Plugin System** | **Built-in** | Not available |
1105
+ | **Result Pattern** | **Built-in** | Not available |
1106
+ | **CLI Tools** | **Built-in** | Not available |
1107
+ | **Codecs** | Built-in, bidirectional | Via external `zod-codecs` |
1108
+ | **Type Inference** | Excellent | Excellent |
1109
+
1110
+ ### Seamless Migration from Zod
1063
1111
 
1064
- ### Simple Migration
1065
1112
  ```javascript
1066
1113
  // Before (Zod)
1067
1114
  import { z } from 'zod';
@@ -1072,32 +1119,26 @@ import { v } from '@oxog/vld';
1072
1119
  const schema = v.string().email();
1073
1120
  ```
1074
1121
 
1075
- ### Why Migrate?
1076
- - **⚡ Performance**: 2-4x faster for most operations
1077
- - **💾 Memory**: Uses 1.18-1.82x less memory than Zod
1078
- - **🌍 Internationalization**: Built-in 27+ language support
1079
- - **📦 Bundle Size**: Smaller with zero dependencies
1080
- - **🔒 Security**: Immutable validators prevent memory leaks
1081
- - **✅ Testing**: 96.55% test coverage with 1142 tests
1082
-
1083
- ## 📈 Benchmarks
1122
+ ## Benchmarks
1084
1123
 
1085
1124
  ### Performance Results
1086
1125
 
1087
- Latest benchmark results show VLD consistently outperforming Zod:
1088
-
1089
1126
  | Test Case | VLD Performance | Improvement |
1090
1127
  |-----------|----------------|-------------|
1091
- | Simple String | 44.4M ops/sec | **1.67x faster** |
1092
- | Email Validation | 18.6M ops/sec | **3.63x faster** |
1093
- | Number Validation | 22.7M ops/sec | **2.62x faster** |
1094
- | Object Validation | 7.6M ops/sec | **1.27x faster** |
1095
- | Array Validation | 6.7M ops/sec | **1.29x faster** |
1096
- | Union Types | 6.8M ops/sec | **1.54x faster** |
1097
- | Optional Values | 32.7M ops/sec | **4.52x faster** |
1098
- | Type Coercion | 18.4M ops/sec | **1.46x faster** |
1099
-
1100
- **Average: 2.52x faster than Zod**
1128
+ | Simple String | 73.0M ops/sec | **2.03x faster** |
1129
+ | Email Validation | 21.8M ops/sec | **3.25x faster** |
1130
+ | Number Validation | 36.3M ops/sec | **3.23x faster** |
1131
+ | Simple Object | 7.1M ops/sec | **1.02x faster** |
1132
+ | Complex Object | 1.9M ops/sec | **1.34x faster** |
1133
+ | Array Validation | 7.5M ops/sec | **1.35x faster** |
1134
+ | Union Types | 7.1M ops/sec | **1.29x faster** |
1135
+ | Optional Values | 36.1M ops/sec | **3.16x faster** |
1136
+ | SafeParse | 60.0M ops/sec | **2.73x faster** |
1137
+ | Type Coercion | 20.4M ops/sec | **1.01x faster** |
1138
+ | Enum Validation | 60.3M ops/sec | **2.08x faster** |
1139
+ | Discriminated Union | 3.6M ops/sec | Zod 1.27x faster |
1140
+
1141
+ **VLD won 11/12 tests | Average: 1.98x faster than Zod**
1101
1142
 
1102
1143
  ### Run Benchmarks
1103
1144
 
@@ -1115,11 +1156,11 @@ npm run benchmark:startup
1115
1156
  npm run benchmark:all
1116
1157
  ```
1117
1158
 
1118
- ## 🤝 Contributing
1159
+ ## Contributing
1119
1160
 
1120
1161
  Contributions are welcome! Please feel free to submit a Pull Request.
1121
1162
 
1122
- ## 🔗 Links
1163
+ ## Links
1123
1164
 
1124
1165
  - [Documentation](https://vld.oxog.dev)
1125
1166
  - [NPM Package](https://www.npmjs.com/package/@oxog/vld)
@@ -1127,4 +1168,4 @@ Contributions are welcome! Please feel free to submit a Pull Request.
1127
1168
 
1128
1169
  ---
1129
1170
 
1130
- Made with ❤️ by [Ersin KOÇ](https://github.com/ersinkoc)
1171
+ Made with Love by [Ersin KOC](https://github.com/ersinkoc)