valleyed 4.4.9 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +253 -179
  3. package/lib/api/arrays.d.ts +4 -8
  4. package/lib/api/arrays.js +55 -43
  5. package/lib/api/arrays.js.map +1 -1
  6. package/lib/api/base/errors.d.ts +19 -0
  7. package/lib/api/base/errors.js +38 -0
  8. package/lib/api/base/errors.js.map +1 -0
  9. package/lib/api/base/index.d.ts +3 -0
  10. package/lib/api/base/index.js +20 -0
  11. package/lib/api/base/index.js.map +1 -0
  12. package/lib/api/base/pipes.d.ts +9 -0
  13. package/lib/api/base/pipes.js +90 -0
  14. package/lib/api/base/pipes.js.map +1 -0
  15. package/lib/api/base/types.d.ts +48 -0
  16. package/lib/api/base/types.js +3 -0
  17. package/lib/api/base/types.js.map +1 -0
  18. package/lib/api/coerce.d.ts +4 -0
  19. package/lib/api/coerce.js +15 -0
  20. package/lib/api/coerce.js.map +1 -0
  21. package/lib/api/core.d.ts +17 -18
  22. package/lib/api/core.js +67 -46
  23. package/lib/api/core.js.map +1 -1
  24. package/lib/{rules/index.d.ts → api/externals.d.ts} +8 -6
  25. package/lib/{rules/index.js → api/externals.js} +11 -7
  26. package/lib/api/externals.js.map +1 -0
  27. package/lib/api/files.d.ts +7 -7
  28. package/lib/api/files.js +36 -18
  29. package/lib/api/files.js.map +1 -1
  30. package/lib/api/index.d.ts +1 -40
  31. package/lib/api/index.js +35 -43
  32. package/lib/api/index.js.map +1 -1
  33. package/lib/api/junctions.d.ts +6 -11
  34. package/lib/api/junctions.js +58 -50
  35. package/lib/api/junctions.js.map +1 -1
  36. package/lib/api/numbers.d.ts +7 -10
  37. package/lib/api/numbers.js +39 -28
  38. package/lib/api/numbers.js.map +1 -1
  39. package/lib/api/optionals.d.ts +11 -0
  40. package/lib/api/optionals.js +52 -0
  41. package/lib/api/optionals.js.map +1 -0
  42. package/lib/api/records.d.ts +13 -7
  43. package/lib/api/records.js +99 -45
  44. package/lib/api/records.js.map +1 -1
  45. package/lib/api/strings.d.ts +10 -15
  46. package/lib/api/strings.js +70 -44
  47. package/lib/api/strings.js.map +1 -1
  48. package/lib/api/times.d.ts +7 -11
  49. package/lib/api/times.js +31 -24
  50. package/lib/api/times.js.map +1 -1
  51. package/lib/api/types.d.ts +8 -0
  52. package/lib/api/types.js +45 -0
  53. package/lib/api/types.js.map +1 -0
  54. package/lib/index.d.ts +4 -6
  55. package/lib/index.js +27 -8
  56. package/lib/index.js.map +1 -1
  57. package/lib/utils/classes.d.ts +9 -10
  58. package/lib/utils/classes.js +21 -28
  59. package/lib/utils/classes.js.map +1 -1
  60. package/lib/utils/differ.d.ts +4 -6
  61. package/lib/utils/differ.js +109 -92
  62. package/lib/utils/differ.js.map +1 -1
  63. package/lib/utils/functions/index.d.ts +2 -0
  64. package/lib/utils/functions/index.js +6 -2
  65. package/lib/utils/functions/index.js.map +1 -1
  66. package/lib/utils/functions/urls/normalize.js.map +1 -1
  67. package/lib/utils/geohash.d.ts +12 -15
  68. package/lib/utils/geohash.js +80 -91
  69. package/lib/utils/geohash.js.map +1 -1
  70. package/lib/utils/types.d.ts +66 -9
  71. package/package.json +2 -1
  72. package/lib/api/base.d.ts +0 -33
  73. package/lib/api/base.js +0 -99
  74. package/lib/api/base.js.map +0 -1
  75. package/lib/api/booleans.d.ts +0 -4
  76. package/lib/api/booleans.js +0 -13
  77. package/lib/api/booleans.js.map +0 -1
  78. package/lib/api/objects.d.ts +0 -16
  79. package/lib/api/objects.js +0 -46
  80. package/lib/api/objects.js.map +0 -1
  81. package/lib/api/tuples.d.ts +0 -13
  82. package/lib/api/tuples.js +0 -26
  83. package/lib/api/tuples.js.map +0 -1
  84. package/lib/rules/arrays.d.ts +0 -5
  85. package/lib/rules/arrays.js +0 -55
  86. package/lib/rules/arrays.js.map +0 -1
  87. package/lib/rules/custom.d.ts +0 -1
  88. package/lib/rules/custom.js +0 -10
  89. package/lib/rules/custom.js.map +0 -1
  90. package/lib/rules/equality.d.ts +0 -4
  91. package/lib/rules/equality.js +0 -42
  92. package/lib/rules/equality.js.map +0 -1
  93. package/lib/rules/files.d.ts +0 -9
  94. package/lib/rules/files.js +0 -41
  95. package/lib/rules/files.js.map +0 -1
  96. package/lib/rules/index.js.map +0 -1
  97. package/lib/rules/mimes.json +0 -3158
  98. package/lib/rules/numbers.d.ts +0 -6
  99. package/lib/rules/numbers.js +0 -65
  100. package/lib/rules/numbers.js.map +0 -1
  101. package/lib/rules/records.d.ts +0 -2
  102. package/lib/rules/records.js +0 -26
  103. package/lib/rules/records.js.map +0 -1
  104. package/lib/rules/strings.d.ts +0 -6
  105. package/lib/rules/strings.js +0 -66
  106. package/lib/rules/strings.js.map +0 -1
  107. package/lib/rules/times.d.ts +0 -4
  108. package/lib/rules/times.js +0 -42
  109. package/lib/rules/times.js.map +0 -1
  110. package/lib/rules/tuples.d.ts +0 -7
  111. package/lib/rules/tuples.js +0 -19
  112. package/lib/rules/tuples.js.map +0 -1
  113. package/lib/rules/types.d.ts +0 -4
  114. package/lib/rules/types.js +0 -36
  115. package/lib/rules/types.js.map +0 -1
  116. package/lib/utils/rules.d.ts +0 -23
  117. package/lib/utils/rules.js +0 -40
  118. package/lib/utils/rules.js.map +0 -1
  119. package/lib/validators/index.d.ts +0 -5
  120. package/lib/validators/index.js +0 -40
  121. package/lib/validators/index.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,77 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [4.5.0](https://github.com/kevinand11/valleyed/compare/v4.4.10...v4.5.0) (2025-06-23)
6
+
7
+
8
+ ### Features
9
+
10
+ * accept multiple pipes in .pipe ([7a6ebb2](https://github.com/kevinand11/valleyed/commit/7a6ebb2987449df7092eee26e5293cd3fe71e460))
11
+ * add __update function to allow update after init ([88a2f93](https://github.com/kevinand11/valleyed/commit/88a2f93c5d0403f443678db7ac3e4b17d7588013))
12
+ * add id for json schema ([7499fe5](https://github.com/kevinand11/valleyed/commit/7499fe5fa6305c1c6dcbd679863ae7ff1a6f30b2))
13
+ * allow value functions for all validators that expect a value input ([99276e7](https://github.com/kevinand11/valleyed/commit/99276e79bec45af2ea089474eafe85c01b78279c))
14
+ * better PipeError ([96817b6](https://github.com/kevinand11/valleyed/commit/96817b6c96454cbe8ea3b29ce63ad07b46b67cd3))
15
+ * bubble up config ([b24b8ee](https://github.com/kevinand11/valleyed/commit/b24b8eeb7161a3b9c26c41d2dc4be0ff0d284f6e))
16
+ * coerce and function ([dcd4dc7](https://github.com/kevinand11/valleyed/commit/dcd4dc7a4009ac6e41fdcd8da258d86644c50555))
17
+ * context ([d206e80](https://github.com/kevinand11/valleyed/commit/d206e80d43c5ddcc32504155c8e08cce32c12a92))
18
+ * defaultOnFail sanitizer ([70cbb85](https://github.com/kevinand11/valleyed/commit/70cbb85e26b3f5b39169a43e78586897c1d067f4))
19
+ * files and records pipe apis ([e9cca15](https://github.com/kevinand11/valleyed/commit/e9cca156067ec430b9a805a8b7bf5322247b1d91))
20
+ * forward PipeError cause ([8507e4e](https://github.com/kevinand11/valleyed/commit/8507e4ec1a02b5077c6bf9c71b22e76024cf27a4))
21
+ * fromJson pipe ([df1eafe](https://github.com/kevinand11/valleyed/commit/df1eafe90d739b63c900afdb24e85f293751944e))
22
+ * generate json schema ([848ed78](https://github.com/kevinand11/valleyed/commit/848ed787c795b92879bec7fe8be59be5af8a3110))
23
+ * isType supports any ([8584398](https://github.com/kevinand11/valleyed/commit/858439840f75bc4ebbbb009b0124fbbbeb480c02))
24
+ * merge pipe ([005acb0](https://github.com/kevinand11/valleyed/commit/005acb01501cd5dd630f9c5ccefe7033206102ca))
25
+ * meta on schema ([620143c](https://github.com/kevinand11/valleyed/commit/620143c80033205fe23206066d2a97a953a26c15))
26
+ * more primitives ([f15ce01](https://github.com/kevinand11/valleyed/commit/f15ce0143cb21d2161050a7060ab4dd4367d292f))
27
+ * new type ConditionalObjectKeys ([6829317](https://github.com/kevinand11/valleyed/commit/6829317c42bcf0dcec4f8614adf49171f369b573))
28
+ * numbers pipe api ([9d1a5ab](https://github.com/kevinand11/valleyed/commit/9d1a5ab1a7709fc025d74c58ef5142744f48228d))
29
+ * object extends ([129f32d](https://github.com/kevinand11/valleyed/commit/129f32de7dfe4f553251008ac4b2ffba95e75fd4))
30
+ * objectExtends, objectPick and objectOmit ([6a89dc3](https://github.com/kevinand11/valleyed/commit/6a89dc367a3cb89bd579d600b282b677d395a7d8))
31
+ * objectMerge ([2117fae](https://github.com/kevinand11/valleyed/commit/2117fae7dc2fde1e553657d7f5f47c72de58c038))
32
+ * optionals api ([29a6fdc](https://github.com/kevinand11/valleyed/commit/29a6fdc878fbc0075a6ac285a09706ac075f7b40))
33
+ * pipe api with primitives, junctions, core and arrays ([e9d2a69](https://github.com/kevinand11/valleyed/commit/e9d2a693b655016bd8c3caaaa15b1ae19a3e7954))
34
+ * pipe node and gather when needed ([dc364b2](https://github.com/kevinand11/valleyed/commit/dc364b21992534cc31a107c93afb59d61cba07df))
35
+ * refactor entire src for treeshaking ([254988d](https://github.com/kevinand11/valleyed/commit/254988d0c6fea4b3f15312fdddc9f73655f61b99))
36
+ * remove need for anyOf in nullable schemas ([2bb3d00](https://github.com/kevinand11/valleyed/commit/2bb3d0043ef6f3e9ebf0a4d63c51512cebb4a051))
37
+ * remove need for static list of files ([3d2d622](https://github.com/kevinand11/valleyed/commit/3d2d622067a9b29803e7c34bb3c2fc2cfe1baefb))
38
+ * strings pipe api ([04c6df8](https://github.com/kevinand11/valleyed/commit/04c6df8b4a5d693efcf41c8680a5e7dfcea79ea4))
39
+ * support custom context ([8530f8e](https://github.com/kevinand11/valleyed/commit/8530f8e8e7e423c425656af2c5bcfac61dae5684))
40
+ * support generics for file validations ([e5cb7b4](https://github.com/kevinand11/valleyed/commit/e5cb7b45d8f2097520cc2515b9da85430a47f327))
41
+ * support standard-schema ([e8b2c8f](https://github.com/kevinand11/valleyed/commit/e8b2c8fe115b1995d8a67cbbd20efec126df7345))
42
+ * switch to reverse linked list impl ([831ec48](https://github.com/kevinand11/valleyed/commit/831ec48efcfe19c50c5e459b92fb36572482d045))
43
+ * times pipe api ([1f18b5e](https://github.com/kevinand11/valleyed/commit/1f18b5e470da73de571d276c4a0dbb06e364a49e))
44
+ * withStrippedHtml ([50cfe72](https://github.com/kevinand11/valleyed/commit/50cfe72bc226290345893d33abdb33d697b474b3))
45
+
46
+
47
+ ### Bug Fixes
48
+
49
+ * before and after expects fn not plain values ([b40eb85](https://github.com/kevinand11/valleyed/commit/b40eb8549527d9fabd45fad27f00da244751b27a))
50
+ * context and schema must be objects ([4d26247](https://github.com/kevinand11/valleyed/commit/4d26247b4c668fc70b8f16df480bd35455a6d154))
51
+ * dataclass toJSON only returns original keys ([b1a5452](https://github.com/kevinand11/valleyed/commit/b1a54525c57bfc8fb9abef5959a8f0418d94b725))
52
+ * fix JSONValue of DataClass<any, any> ([6a168c1](https://github.com/kevinand11/valleyed/commit/6a168c1f0af94b878c0870758e96b2ad2e858d75))
53
+ * fix Prettify for class instances ([39d79fb](https://github.com/kevinand11/valleyed/commit/39d79fb70cff7d440f514f82d2b35278a58d7b82))
54
+ * fix typings for objectX rules ([885ea27](https://github.com/kevinand11/valleyed/commit/885ea27adbb0d1dc3726454bb250057aaca19279))
55
+ * fix up JSONValueOf ([de97762](https://github.com/kevinand11/valleyed/commit/de977629c8389986613dd3fd6379a68069d719ef))
56
+ * impl for objectPick, objectOmit and objectExtends and add tests ([76a2f6b](https://github.com/kevinand11/valleyed/commit/76a2f6bf674e7e279046e1fb5f24c3424edfaf39))
57
+ * no need to clone for objects ([f1f0f2d](https://github.com/kevinand11/valleyed/commit/f1f0f2d3493d29c359c1d1b1e2d6bffb10260611))
58
+ * objectPick and objectEmit as value ([0f94a9a](https://github.com/kevinand11/valleyed/commit/0f94a9aa7f90e5e2ae6aaba425987a0c01e9b5f1))
59
+ * optionals typing ([4ae6979](https://github.com/kevinand11/valleyed/commit/4ae6979836df939036870ffadd412c903dbc0979))
60
+ * remove need for __update ([11bf277](https://github.com/kevinand11/valleyed/commit/11bf27709645853bbe9dcc0ec8a15dfe3a505996))
61
+ * remove objectTrim ([630f1f0](https://github.com/kevinand11/valleyed/commit/630f1f05cab076344990e61ef5c266453d0f3388))
62
+ * remove Pipe requirement for PipeInput, Output and Context ([0671b1e](https://github.com/kevinand11/valleyed/commit/0671b1e814cdfe6d95911752c13eaa90f1316c27))
63
+ * remove unknown errors ([9d6fd72](https://github.com/kevinand11/valleyed/commit/9d6fd72fcc9067d6263f924f4db18d55c0912595))
64
+ * rename safeParse to validate ([6ce2a75](https://github.com/kevinand11/valleyed/commit/6ce2a756ef728d49b61d94b29b0f779dffb5d828))
65
+ * requiredIf doesnt add undefined to the type ([b8054fb](https://github.com/kevinand11/valleyed/commit/b8054fbe0d17cf1fb3904e766636f2a23be28f3c))
66
+ * return type of DataClass toJSON ([9cd66ac](https://github.com/kevinand11/valleyed/commit/9cd66ac94f514979c59ebf50b6f7ff2e15c20c34))
67
+ * stop Prettify from messing with classes ([2c6ca51](https://github.com/kevinand11/valleyed/commit/2c6ca51624e685e9a67720153711bf2abb200c2e))
68
+
69
+ ### [4.4.10](https://github.com/kevinand11/valleyed/compare/v4.4.9...v4.4.10) (2025-06-04)
70
+
71
+
72
+ ### Bug Fixes
73
+
74
+ * type JSONValue of any with toJSON ([0d7d5a8](https://github.com/kevinand11/valleyed/commit/0d7d5a8aae7feed277ffb482e66ec583ed16a0a4))
75
+
5
76
  ### [4.4.9](https://github.com/kevinand11/valleyed/compare/v4.4.8...v4.4.9) (2025-06-04)
6
77
 
7
78
 
package/README.md CHANGED
@@ -1,244 +1,318 @@
1
1
  # Valleyed
2
2
 
3
+ Valleyed is a powerful, type-safe, and lightweight validation library for TypeScript and JavaScript. It provides a fluent, chainable API to build complex validation pipelines with ease, inspired by libraries like Zod, but with a focus on simplicity and extensibility.
3
4
 
4
- ## Installation
5
+ ## ✨ Features
5
6
 
6
- This is a [Node.js](https://nodejs.org/en/) module available through the [npm registry](https://www.npmjs.com/package/valleyed).
7
- Before installing, [download and install Node.js](https://nodejs.org/en/download/). Node.js 4.2.4 or higher is required.
8
- If this is a brand new project, make sure to create a `package.json` first with the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
9
- Installation is done using the [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
7
+ - **Type-Safe**: Full TypeScript support, infer types directly from your schemas.
8
+ - **Lightweight**: Small bundle size with zero dependencies.
9
+ - **Chainable API**: Build complex validations by chaining methods.
10
+ - **Extensible**: Easily add your own custom validation logic.
11
+ - **Standard Schema Compatible**: Generate JSON Schemas from your validation pipes.
12
+ - **Isomorphic**: Works in both Node.js and browser environments.
10
13
 
11
- ### Using npm:
12
- npm install valleyed
14
+ ## 📦 Installation
13
15
 
14
- ### Using yarn:
15
- yarn add valleyed
16
+ You can install Valleyed using your favorite package manager:
16
17
 
17
- ### Using CDN:
18
- [Valleyed jsDelivr CDN](https://www.jsdelivr.com/package/npm/valleyed)
19
-
20
-
21
- ## Basic Usage
22
-
23
- ```ts
24
- import { isEmail, isMinOf } from 'valleyed'
25
-
26
- // The isEmail function builds and returns a function that checks if the first argument is a valid email
27
- let validity = isEmail()('johndoe@mail.co')
28
- console.log(validity)
29
- // Output should be : { valid: true, error: null, value: 'johndoe@mail.co' }
18
+ ```bash
19
+ npm install valleyed
20
+ # or
21
+ yarn add valleyed
22
+ # or
23
+ pnpm add valleyed
24
+ ```
30
25
 
31
- // The isMinOf function builds a function that checks if the first argument is of minimum length of the length passed into the builder function
32
- validity = isMinOf(5)('abcd')
33
- console.log(validity)
34
- // Output should be : { valid: false, error: 'must contain 5 or more characters', value: 'abcd' }
26
+ ## 🚀 Quick Start
27
+
28
+ Here's a quick example to get you started with Valleyed:
29
+
30
+ ```typescript
31
+ import { v } from 'valleyed';
32
+
33
+ // 1. Define a schema for your data
34
+ const userSchema = v.object({
35
+ name: v.string().pipe(v.min(3)),
36
+ email: v.string().pipe(v.email()),
37
+ age: v.optional(v.number().pipe(v.gte(18))),
38
+ });
39
+
40
+ // 2. Some data to validate
41
+ const userData = {
42
+ name: 'John Doe',
43
+ email: 'john.doe@example.com',
44
+ };
45
+
46
+ // 3. Validate the data
47
+ const validationResult = userSchema.validate(userData);
48
+
49
+ if (validationResult.valid) {
50
+ // Type-safe access to the validated data
51
+ console.log('Validation successful:', validationResult.value);
52
+ } else {
53
+ // Detailed error messages
54
+ console.error('Validation failed:', validationResult.error.toString());
55
+ }
56
+
57
+ // 4. You can also parse directly, which throws on error
58
+ try {
59
+ const user = userSchema.parse(userData);
60
+ console.log('Parsed user:', user);
61
+ } catch (error) {
62
+ console.error(error);
63
+ }
35
64
  ```
36
65
 
66
+ ## 📚 API Reference
37
67
 
38
- ## Common Rule Builders
68
+ Valleyed exports a single object `v` which contains all the validation functions.
39
69
 
40
- ### Errors
70
+ ### Primitive Types
41
71
 
42
- All rule builders accept an optional string as the last argument used to customize the error message
72
+ These are the basic building blocks for any schema.
43
73
 
44
- ```ts
45
- const res = isEmail('is missing specific characters')('')
46
- console.log(res) // { valid: false, error: 'is missing specific characters', value: '' }
47
- ```
74
+ | Function | Description |
75
+ | ---------------- | ---------------------------------------------------- |
76
+ | `v.string()` | Checks if the input is a `string`. |
77
+ | `v.number()` | Checks if the input is a `number` (and not `NaN`). |
78
+ | `v.boolean()` | Checks if the input is a `boolean`. |
79
+ | `v.null()` | Checks if the input is `null`. |
80
+ | `v.undefined()` | Checks if the input is `undefined`. |
81
+ | `v.any()` | Allows any value, essentially a pass-through. |
82
+ | `v.instanceOf()` | Checks if the input is an instance of a given class. |
48
83
 
49
- ### Equality
84
+ ```typescript
85
+ // Example:
86
+ v.string().validate('hello').valid; // true
87
+ v.number().validate(123).valid; // true
88
+ v.instanceOf(Date).validate(new Date()).valid; // true
89
+ ```
50
90
 
51
- ```ts
52
- // Checks if the validation value is shallow equal to the compare. Valuable for comparing primitive types
53
- isShallowEqualTo(compare)
91
+ ### Core Validators
92
+
93
+ These validators can be piped from any other validator to add more constraints.
94
+
95
+ | Function | Description |
96
+ | ------------------------- | ------------------------------------------------------------------------ |
97
+ | `v.custom(fn, msg?)` | Validates using a custom function that returns a boolean. |
98
+ | `v.eq(val, msg?)` | Checks for deep equality with a given value. Alias: `v.is()`. |
99
+ | `v.ne(val, msg?)` | Checks for deep inequality with a given value. |
100
+ | `v.in(arr, msg?)` | Checks if the value is present in the provided array. |
101
+ | `v.nin(arr, msg?)` | Checks if the value is **not** present in the provided array. |
102
+ | `v.has(len, msg?)` | For strings and arrays, checks for an exact length. |
103
+ | `v.min(len, msg?)` | For strings and arrays, checks for a minimum length. |
104
+ | `v.max(len, msg?)` | For strings and arrays, checks for a maximum length. |
105
+
106
+ ```typescript
107
+ // Example:
108
+ const schema = v.string().pipe(v.min(5), v.in(['hello', 'world']));
109
+ schema.validate('hello').valid; // true
110
+ schema.validate('hi').valid; // false (fails min(5))
111
+ schema.validate('testing').valid; // false (fails in([...]))
112
+ ```
54
113
 
55
- // Checks if the validation value resolves to true when passed into the compareFunction. The compareFunction passes the validation value and the compare value as the arguments and expects a boolean in return. Valuable for comparing non-primitive types.
56
- isDeepEqualTo(compare, compareFunction)
57
- const res = isDeepEqualTo({ id: 1 }, (value, compare) => {
58
- return value?.id === compare.id
59
- })({ id: 1 }) // res.valid is true
114
+ ### String Validators
60
115
 
61
- // Checks if the validation value is in an array of predefined values
62
- arrayContains(array, compareFunction)
63
- const res = arrayContains([{ id: 1 }, { id: 2 }], (value, compare) => {
64
- return value?.id === compare.id
65
- })({ id: 2 }) // res.valid is true
66
- ```
116
+ Specific validators and transformers for strings.
67
117
 
68
- ### Strings
118
+ | Function | Description |
119
+ | -------------------- | ------------------------------------------------------------------------ |
120
+ | `v.email(msg?)` | Validates an email address format. |
121
+ | `v.url(msg?)` | Validates a URL format. |
122
+ | `v.asTrimmed()` | **Transformer**: Trims whitespace from the start and end of a string. |
123
+ | `v.asLowercased()` | **Transformer**: Converts the string to lowercase. |
124
+ | `v.asUppercased()` | **Transformer**: Converts the string to uppercase. |
125
+ | `v.asCapitalized()` | **Transformer**: Capitalizes each word in the string. |
126
+ | `v.asStrippedHtml()` | **Transformer**: Removes HTML tags from the string. |
127
+ | `v.asSliced(len)` | **Transformer**: Slices the string to a max length, adding `...`. |
128
+ | `v.withStrippedHtml(pipe)` | Applies a validation pipe to an HTML-stripped version of the string, but returns the original string if valid. |
69
129
 
70
- ```ts
71
- // Checks if the validation value is of type String. This is used internally in all string methods, so no need to use it unless you are making a custom rule
72
- isString()
130
+ ```typescript
131
+ // Example:
132
+ v.string().pipe(v.email()).validate('test@example.com').valid; // true
73
133
 
74
- // Checks if the length of the validation value is equal to the length
75
- isLengthOf(length)
134
+ const trimmedLower = v.string().pipe(v.asTrimmed(), v.asLowercased());
135
+ trimmedLower.parse(' HeLLo '); // 'hello'
136
+ ```
76
137
 
77
- // Checks if the length of the validation value is greater than or equal to the length
78
- isMinOf(length)
138
+ ### Number Validators
79
139
 
80
- // Checks if the length of the validation value is less than or equal to the length
81
- isMaxOf(length)
140
+ Specific validators and transformers for numbers.
82
141
 
83
- // Checks if the validation value is formatted as a valid email
84
- isEmail()
142
+ | Function | Description |
143
+ | ----------------- | -------------------------------------------------------- |
144
+ | `v.gt(num, msg?)` | Checks if the number is greater than the given value. |
145
+ | `v.gte(num, msg?)`| Checks if the number is greater than or equal to the given value. |
146
+ | `v.lt(num, msg?)` | Checks if the number is less than the given value. |
147
+ | `v.lte(num, msg?)`| Checks if the number is less than or equal to the given value. |
148
+ | `v.int(msg?)` | Checks if the number is an integer. |
149
+ | `v.asRounded(dp?)`| **Transformer**: Rounds the number to a number of decimal places. |
85
150
 
86
- // Checks if the validation value is formatted as a valid url
87
- isUrl()
151
+ ```typescript
152
+ // Example:
153
+ const ageSchema = v.number().pipe(v.int(), v.gte(18));
154
+ ageSchema.validate(25).valid; // true
155
+ ageSchema.validate(17.5).valid; // false
88
156
  ```
89
157
 
90
- ### Numbers
91
-
92
- ```ts
93
- // Checks if the validation value is of type Number. This is used internally in all number methods, so no need to use it unless you are making a custom rule
94
- isNumber()
158
+ ### Array Validators
95
159
 
96
- // Checks if the the validation value is greater than the compare
97
- isMoreThan(compare)
160
+ Validators for handling arrays.
98
161
 
99
- // Checks if the the validation value is greater than or equal to the compare
100
- isMoreThanOrEqualTo(compare)
162
+ | Function | Description |
163
+ | ------------------------- | ------------------------------------------------------------------------ |
164
+ | `v.array(schema)` | Validates that every element in an array matches the provided schema. |
165
+ | `v.tuple([s1, s2])` | Validates a fixed-length array where each element has a specific type. |
166
+ | `v.asSet(keyFn?)` | **Transformer**: Removes duplicates from an array. By default, it uses the value itself for comparison. You can provide a `keyFn` for objects. |
101
167
 
102
- // Checks if the the validation value is less than the compare
103
- isLessThan(compare)
168
+ ```typescript
169
+ // Example:
170
+ const tagsSchema = v.array(v.string().pipe(v.min(2)));
171
+ tagsSchema.validate(['food', 'travel']).valid; // true
104
172
 
105
- // Checks if the the validation value is less than or equal to the compare
106
- isLessThanOrEqualTo(compare)
173
+ const pointSchema = v.tuple([v.number(), v.number()]);
174
+ pointSchema.validate([10, 20]).valid; // true
107
175
  ```
108
176
 
109
- ### Arrays
177
+ ### Object Validators
110
178
 
111
- ```ts
112
- // Checks if the validation value is of type Array. This is used internally in all array methods, so no need to use it unless you are making a custom rule
113
- isArray()
179
+ Validators for handling objects.
114
180
 
115
- // Checks if the length of the validation value is equal to the length
116
- hasLengthOf(length)
181
+ | Function | Description |
182
+ | ------------------------------- | ------------------------------------------------------------------------ |
183
+ | `v.object({ k: schema })` | Validates an object's properties against a schema definition. |
184
+ | `v.record(keySchema, valSchema)`| Validates objects with dynamic keys (like dictionaries or records). |
185
+ | `v.objectPick(schema, keys)` | Creates a new object schema by picking specified keys from an existing one. |
186
+ | `v.objectOmit(schema, keys)` | Creates a new object schema by omitting specified keys from an existing one. |
187
+ | `v.objectExtends(schema, pipes)`| Extends an object schema with new properties. |
188
+ | `v.asMap()` | **Transformer**: Converts a record-like object into a `Map`. |
117
189
 
118
- // Checks if the length of the validation value is greater than or equal to the length
119
- hasMinOf(length)
190
+ ```typescript
191
+ // Example:
192
+ const userSchema = v.object({ name: v.string(), age: v.number() });
120
193
 
121
- // Checks if the length of the validation value is less than or equal to the length
122
- hasMaxOf(length)
194
+ const publicUserSchema = v.objectOmit(userSchema, ['age']);
195
+ publicUserSchema.validate({ name: 'John' }).valid; // true
123
196
 
124
- // Checks if the validation value is formatted as a valid email
125
- isEmail()
126
-
127
- // Checks if all elements in the valition value passes a requirement. The compare function passes a element and its index as the arguments and expects a boolean in return.
128
- isArrayOf(compareFunction)
129
- const res = isArrayOf((element, index) => {
130
- return isString(element).valid // This ensures all elements in the array are strings
131
- })(['a', 'b', 'c']) // res.valid is true
197
+ const userWithIdSchema = v.objectExtends(userSchema, { id: v.string() });
198
+ userWithIdSchema.validate({ id: 'user-1', name: 'Jane', age: 30 }).valid; // true
199
+ ```
132
200
 
133
- // Used to validate tuples(arrays that can contain different data types). Checks if all elements in the validation values passes a different requirement
134
- isTuple(compareFunctionsArray)
135
- const res = isTuple([
136
- (element, index) => isString(element).valid,
137
- (element, index) => isNumber(element).valid
138
- ])(['hello world', 2]) // res.valid is true because it expects an array that contains a string at index 0 and a number at index 1
201
+ ### Optional & Default Values
202
+
203
+ Functions for handling optional values and providing defaults.
204
+
205
+ | Function | Description |
206
+ | ------------------------------ | ------------------------------------------------------------------------ |
207
+ | `v.optional(schema)` | Allows the value to be `undefined`. |
208
+ | `v.nullable(schema)` | Allows the value to be `null`. |
209
+ | `v.nullish(schema)` | Allows the value to be `null` or `undefined`. |
210
+ | `v.defaults(schema, val)` | Provides a default value if the input is `undefined`. |
211
+ | `v.defaultsOnFail(schema, val)`| Provides a default value if the initial validation fails. |
212
+ | `v.conditional(schema, fn)` | Makes a field optional based on a dynamic boolean condition. |
213
+
214
+ ```typescript
215
+ // Example:
216
+ const schema = v.object({
217
+ name: v.string(),
218
+ nickname: v.optional(v.string()),
219
+ role: v.defaults(v.string(), 'user'),
220
+ });
221
+
222
+ schema.parse({ name: 'John' });
223
+ // { name: 'John', role: 'user' }
139
224
  ```
140
225
 
141
- ### Datetime
226
+ ### Junctions (Unions & Intersections)
142
227
 
143
- ```ts
144
- // Checks if the validation value can be parsed into a valid javascript date. Validation value can be a Date object, a timestamp number or a datetime string. This is used internally in all datetime methods, so no need to use it unless you are making a custom rule
145
- isTime()
228
+ Combine schemas to create complex types.
146
229
 
147
- // Checks if the validation value is later than the compare. Compare can also be a Date object, a timestamp number or a datetime string
148
- isLaterThan(compare)
230
+ | Function | Description |
231
+ | -------------------------------------- | ------------------------------------------------------------------------ |
232
+ | `v.or([s1, s2])` | A union type. The value must match at least one of the provided schemas. |
233
+ | `v.and([s1, s2])` | An intersection. The value must match all of the provided schemas. |
234
+ | `v.merge(s1, s2)` | Merges two object or array schemas. |
235
+ | `v.discriminate(fn, schemas)` | Validates against one of several object schemas based on a discriminator field. |
236
+ | `v.fromJson(schema)` | **Transformer**: Parses a JSON string before validating against a schema. |
149
237
 
150
- // Checks if the validation value is earlier than the compare. Compare can also be a Date object, a timestamp number or a datetime string
151
- isEarlierThan(compare)
152
- ```
238
+ ```typescript
239
+ // Example: Discriminated Union
240
+ const shapeSchema = v.discriminate(v => v.type, {
241
+ circle: v.object({ type: v.is('circle'), radius: v.number() }),
242
+ square: v.object({ type: v.is('square'), side: v.number() }),
243
+ });
153
244
 
154
- ### Other Types
155
-
156
- ```ts
157
- // Checks if the validation value is a boolean
158
- isBoolean()
245
+ shapeSchema.validate({ type: 'circle', radius: 10 }).valid; // true
246
+ shapeSchema.validate({ type: 'square', side: 5 }).valid; // true
247
+ ```
159
248
 
160
- // Checks if the validation value is null
161
- isNull()
249
+ ### Date & Time Validators
162
250
 
163
- // Checks if the validation value is undefined
164
- isUndefined()
251
+ Validators and transformers for dates and times.
165
252
 
166
- // Checks if the validation value is an instance of the Class passed in
167
- isInstanceOf(classDefinition)
168
- const res = isInstanceOf(String)('') // res.valid is true
169
- ```
253
+ | Function | Description |
254
+ | ------------------- | ------------------------------------------------------------------------ |
255
+ | `v.time(msg?)` | Validates a date, accepting `Date` objects, timestamps, or date strings. |
256
+ | `v.after(date, msg?)`| Checks if the date is after a specified date. |
257
+ | `v.before(date, msg?)`| Checks if the date is before a specified date. |
258
+ | `v.asStamp()` | **Transformer**: Converts a `Date` object into a numeric timestamp. |
259
+ | `v.asISOString()` | **Transformer**: Converts a `Date` object into an ISO 8601 string. |
170
260
 
171
- ### Records and Maps
172
-
173
- ```ts
174
- /// Checks if all values in an object passes a comparer function
175
- isRecord(compareFunction)
176
- const res = isRecord((currentValue) => {
177
- return isNumber(currentValue).valid
178
- })({ a: 1, b: 2, c: 3 }) // res.valid is true because all the values of the object are numbers
179
-
180
- /// Checks if all keys and values in an map passes a comparer function
181
- isMap(keysCompareFunction, valuesCompareFunction)
182
- const map = new Map([
183
- [1, true],
184
- [2, false],
185
- [3, true]
186
- ])
187
- const res = isMap(
188
- (key) => isNumber(key).valid,
189
- (value) => isBoolean(value).valid
190
- )(map) // res.valid is true because all the keys of the map are numbers and all the values are booleans
261
+ ```typescript
262
+ // Example:
263
+ const eventSchema = v.object({
264
+ name: v.string(),
265
+ startsAt: v.time().pipe(v.after(new Date())),
266
+ });
191
267
  ```
192
268
 
193
- ### Files
194
-
195
- ```ts
196
- // Checks if the validation value is an object with a key "type" that contains a supported file mimetypes. All supported file mimetypes can be imported under the name "fileMimeTypes". This is used internally in all file methods, so no need to use it unless you are making a custom rule
197
- isFile()
269
+ ### File Validators
198
270
 
199
- // Checks if the validation value's type is a valid image mimetype. All supported image mimetypes can be imported under the name "imageMimeTypes".
200
- isImage()
271
+ Validators for file-like objects (e.g., from a file upload). These validators expect an object with a `type` property containing the MIME type.
201
272
 
202
- // Checks if the validation value's type is a valid audio mimetype. All supported audio mimetypes can be imported under the name "audioMimeTypes".
203
- isAudio()
273
+ | Function | Description |
274
+ | ----------------------------- | ------------------------------------------------------------------------ |
275
+ | `v.file(msg?)` | Validates a generic file-like object. |
276
+ | `v.image(msg?)` | Validates if the file is an image (`image/*`). |
277
+ | `v.audio(msg?)` | Validates if the file is an audio file (`audio/*`). |
278
+ | `v.video(msg?)` | Validates if the file is a video file (`video/*`). |
279
+ | `v.fileType(types, msg?)` | Validates if the file's MIME type is in the provided list. |
204
280
 
205
- // Checks if the validation value's type is a valid video mimetype. All supported video mimetypes can be imported under the name "videoMimeTypes".
206
- isVideo()
281
+ ```typescript
282
+ // Example:
283
+ const imageSchema = v.file().pipe(v.image(), v.fileType(['image/jpeg', 'image/png']));
284
+ imageSchema.validate({ type: 'image/png' }).valid; // true
285
+ imageSchema.validate({ type: 'image/gif' }).valid; // false
207
286
  ```
208
287
 
209
- ### Custom Rule
288
+ ### Coercion
210
289
 
211
- ```ts
212
- // If there is a rule for your usecase, you can create a custom one with this. The validityFunction passes the validation value as its argument and expects a boolean in return
213
- isCustom(validityFunction)
214
- const res = isCustom((value) => typeof value === 'function')(() => {}) // res.valid is true because the typeof value is function
215
- ```
290
+ These pipes attempt to convert the input to a specific type before validating it.
216
291
 
292
+ | Function | Description |
293
+ | ------------------- | ------------------------------------------------------------------------ |
294
+ | `v.coerceString()` | Coerces to `string` using `String()`. |
295
+ | `v.coerceNumber()` | Coerces to `number` using `Number()`. Fails if the result is `NaN`. |
296
+ | `v.coerceBoolean()` | Coerces to `boolean` using `Boolean()`. |
297
+ | `v.coerceTime()` | Coerces to `Date` using `new Date()`. |
217
298
 
218
- ## Combining Rules
299
+ ```typescript
300
+ // Example:
301
+ const schema = v.coerceNumber().pipe(v.int());
302
+ schema.parse('123'); // 123
303
+ schema.validate('123.45').valid; // false (fails int())
304
+ ```
219
305
 
220
- ```ts
221
- import { Validator, isEmail, isMinOf, isString, isNumber } from 'valleyed'
306
+ ## 🤝 Contributing
222
307
 
223
- // The Validator.and function is used to build up a schema or list of rules to validate a value against
224
- let res = Validator.and([[isEmail(), isMinOf(1)]])('johndoe@mail.com')
225
- console.log(res) // { valid: true, errors: [], value: 'johndoe@mail.com' }
308
+ Contributions are welcome! Please open an issue or submit a pull request.
226
309
 
227
- // if the value fails validation, it returns a list of all errors in the errors array
228
- res = Validator.and([[isEmail(), isMinOf(1)]])('')
229
- console.log(res) // { valid: false, value: '', errors: [ 'is not a valid email', 'must contain 1 or more characters' ] }
310
+ ### Development Setup
230
311
 
231
- // Similar to the And function, Validator has an or function that checks if the value passes validation for any of the list of rules passed in
232
- let res = Validator.or([[isString(), isMinOf(1)], [isNumber()]])(2)
233
- console.log(res) // { valid: true, value: 2, errors: [] }
312
+ 1. Clone the repository.
313
+ 2. Install dependencies with `pnpm install`.
314
+ 3. Run tests with `pnpm test`.
234
315
 
235
- // if the value fails validation, it returns a list of all errors in the errors array
236
- res = Validator.or([[isString(), isMinOf(1)], [isNumber()]])(false)
237
- console.log(res) // { valid: false, value: false, errors: [ 'doesn't match any of the schema' ] }
316
+ ## 📜 License
238
317
 
239
- // An optional third paramater can be passed into the And/Or functions to control if null and undefined are allowed to pass validation
240
- Validator.and([[isEmail()]], {
241
- nullable: true, // Boolean: if true, null passed as the first argument passes validation
242
- required: () => false // Boolean or Function that returns a boolean: if false, undefined passed as the first argument passes validation
243
- })('')
244
- ```
318
+ This project is licensed under the MIT License.
@@ -1,8 +1,4 @@
1
- import { VCore } from './core';
2
- export declare class VArray<I> extends VCore<I[]> {
3
- constructor(comparer: VCore<I>, err?: string);
4
- has(length: number, err?: string): this;
5
- min(length: number, err?: string): this;
6
- max(length: number, err?: string): this;
7
- set(keyFn?: (v: I) => any): this;
8
- }
1
+ import { PipeInput, type Pipe, type PipeOutput } from './base';
2
+ export declare const array: <T extends Pipe<any, any, any>>(pipeSchema: T) => Pipe<PipeInput<T>[], PipeOutput<T>[], any>;
3
+ export declare const tuple: <T extends ReadonlyArray<Pipe<any, any, any>>>(pipes: readonly [...T]) => Pipe<{ [K in keyof T]: PipeInput<T[K]>; }, { [K_1 in keyof T]: PipeOutput<T[K_1]>; }, any>;
4
+ export declare const asSet: <T>(keyFn?: (i: T) => PropertyKey) => Pipe<T[], T[], any>;