@amazon/vinyl-validation 1.1.0 → 1.2.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.
- package/{docs/VALIDATION.md → README.md} +50 -91
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/types/current/validation/FunctionSchema.js +1 -1
- package/dist/types/current/validation/ObjectSchema.d.ts +2 -2
- package/dist/types/current/validation/ObjectSchema.d.ts.map +1 -1
- package/dist/types/current/validation/PropertyValidator.d.ts +1 -1
- package/dist/types/current/validation/PropertyValidator.d.ts.map +1 -1
- package/dist/types/ts3.7/validation/ObjectSchema.d.ts +2 -2
- package/dist/types/ts3.7/validation/PropertyValidator.d.ts +1 -1
- package/dist/types/ts4.1/validation/ObjectSchema.d.ts +2 -2
- package/dist/types/ts4.1/validation/PropertyValidator.d.ts +1 -1
- package/dist/types/ts4.7/validation/ObjectSchema.d.ts +2 -2
- package/dist/types/ts4.7/validation/PropertyValidator.d.ts +1 -1
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -0
- package/package.json +8 -11
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @amazon/vinyl-validation
|
|
2
|
+
|
|
3
|
+
[](https://amazonmusic.github.io/vinyl)
|
|
4
|
+
[](https://www.npmjs.com/package/@amazon/vinyl-validation)
|
|
5
|
+
[](https://bundlejs.com/?q=@amazon/vinyl-validation)
|
|
2
6
|
|
|
3
7
|
A TypeScript-first validation library for runtime type checking and schema
|
|
4
|
-
validation.
|
|
8
|
+
validation. Composable validators for primitives, objects, arrays, sets,
|
|
9
|
+
records, tuples, functions, and unions, with strong inference of the result
|
|
10
|
+
type.
|
|
5
11
|
|
|
6
|
-
##
|
|
12
|
+
## Install
|
|
7
13
|
|
|
8
|
-
```
|
|
14
|
+
```shell
|
|
9
15
|
npm install @amazon/vinyl-validation
|
|
10
16
|
```
|
|
11
17
|
|
|
12
18
|
## Basic Usage
|
|
13
19
|
|
|
14
20
|
```typescript
|
|
15
|
-
import { string, number
|
|
21
|
+
import { string, number } from '@amazon/vinyl-validation'
|
|
16
22
|
|
|
17
|
-
// Create validators
|
|
18
23
|
const nameValidator = string().notEmpty()
|
|
19
24
|
const ageValidator = number().gte(0)
|
|
20
25
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
console.log(ageValidator.isValid(-5)) // false
|
|
26
|
+
nameValidator.isValid('John') // true
|
|
27
|
+
ageValidator.isValid(-5) // false
|
|
24
28
|
|
|
25
29
|
// Get validation errors
|
|
26
30
|
const errors = nameValidator.validate('')
|
|
27
|
-
|
|
31
|
+
// [{ message: 'Expected: not empty, but was: "". At: ', path: [] }]
|
|
28
32
|
```
|
|
29
33
|
|
|
30
34
|
## Core Validators
|
|
@@ -60,10 +64,8 @@ const nullishValidator = nullish() // null or undefined
|
|
|
60
64
|
```typescript
|
|
61
65
|
import { isOneOf, instanceOf } from '@amazon/vinyl-validation'
|
|
62
66
|
|
|
63
|
-
// Literal values
|
|
64
67
|
const statusValidator = isOneOf('active', 'inactive', 'pending')
|
|
65
68
|
|
|
66
|
-
// Instance checking
|
|
67
69
|
const dateValidator = instanceOf(Date)
|
|
68
70
|
const errorValidator = instanceOf(Error)
|
|
69
71
|
```
|
|
@@ -74,13 +76,12 @@ const errorValidator = instanceOf(Error)
|
|
|
74
76
|
import { string } from '@amazon/vinyl-validation'
|
|
75
77
|
|
|
76
78
|
const validator = string()
|
|
77
|
-
.notEmpty()
|
|
78
|
-
.minLength(3)
|
|
79
|
-
.maxLength(50)
|
|
80
|
-
.noWhitespace()
|
|
81
|
-
.matches(/^[a-z]+$/)
|
|
79
|
+
.notEmpty()
|
|
80
|
+
.minLength(3)
|
|
81
|
+
.maxLength(50)
|
|
82
|
+
.noWhitespace()
|
|
83
|
+
.matches(/^[a-z]+$/)
|
|
82
84
|
|
|
83
|
-
// Usage
|
|
84
85
|
validator.isValid('hello') // true
|
|
85
86
|
validator.isValid('') // false (empty)
|
|
86
87
|
validator.isValid('ab') // false (too short)
|
|
@@ -91,16 +92,8 @@ validator.isValid('ab') // false (too short)
|
|
|
91
92
|
```typescript
|
|
92
93
|
import { number } from '@amazon/vinyl-validation'
|
|
93
94
|
|
|
94
|
-
const validator = number()
|
|
95
|
-
.gte(0) // greater than or equal to 0
|
|
96
|
-
.gt(0) // greater than 0
|
|
97
|
-
.lte(100) // less than or equal to 100
|
|
98
|
-
.lt(100) // less than 100
|
|
99
|
-
.within(1, 99) // between 1 and 99 (inclusive)
|
|
100
|
-
.safeInteger() // safe integer
|
|
101
|
-
.finite() // finite number
|
|
95
|
+
const validator = number().gte(0).lte(100).within(1, 99).safeInteger().finite()
|
|
102
96
|
|
|
103
|
-
// Usage
|
|
104
97
|
validator.isValid(50) // true
|
|
105
98
|
validator.isValid(-1) // false (less than 0)
|
|
106
99
|
validator.isValid(Infinity) // false (not finite)
|
|
@@ -109,7 +102,13 @@ validator.isValid(Infinity) // false (not finite)
|
|
|
109
102
|
## Object Validation
|
|
110
103
|
|
|
111
104
|
```typescript
|
|
112
|
-
import {
|
|
105
|
+
import {
|
|
106
|
+
object,
|
|
107
|
+
string,
|
|
108
|
+
number,
|
|
109
|
+
isOneOf,
|
|
110
|
+
array,
|
|
111
|
+
} from '@amazon/vinyl-validation'
|
|
113
112
|
|
|
114
113
|
const userValidator = object({
|
|
115
114
|
name: string().notEmpty(),
|
|
@@ -117,9 +116,8 @@ const userValidator = object({
|
|
|
117
116
|
email: string().matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/),
|
|
118
117
|
})
|
|
119
118
|
|
|
120
|
-
// Usage
|
|
121
119
|
const user = { name: 'John', age: 30, email: 'john@example.com' }
|
|
122
|
-
|
|
120
|
+
userValidator.isValid(user) // true
|
|
123
121
|
|
|
124
122
|
// Extend existing schemas
|
|
125
123
|
const adminValidator = userValidator.extend({
|
|
@@ -131,22 +129,19 @@ const adminValidator = userValidator.extend({
|
|
|
131
129
|
## Array Validation
|
|
132
130
|
|
|
133
131
|
```typescript
|
|
134
|
-
import { array, string, number, tuple } from '@amazon/vinyl-validation'
|
|
132
|
+
import { array, string, number, tuple, boolean } from '@amazon/vinyl-validation'
|
|
135
133
|
|
|
136
|
-
// Array of strings
|
|
137
134
|
const stringArrayValidator = array(string())
|
|
138
135
|
|
|
139
|
-
// Array of numbers with constraints
|
|
140
136
|
const numberArrayValidator = array(number().gte(0))
|
|
141
|
-
.minLength(1)
|
|
142
|
-
.maxLength(10)
|
|
143
|
-
.notEmpty()
|
|
137
|
+
.minLength(1)
|
|
138
|
+
.maxLength(10)
|
|
139
|
+
.notEmpty()
|
|
144
140
|
|
|
145
|
-
//
|
|
141
|
+
// Tuples (fixed-length, positional)
|
|
146
142
|
const coordinateValidator = tuple(number(), number()) // [x, y]
|
|
147
143
|
const personValidator = tuple(string(), number(), boolean()) // [name, age, active]
|
|
148
144
|
|
|
149
|
-
// Usage
|
|
150
145
|
stringArrayValidator.isValid(['a', 'b', 'c']) // true
|
|
151
146
|
coordinateValidator.isValid([10, 20]) // true
|
|
152
147
|
coordinateValidator.isValid([10, 20, 30]) // false (wrong length)
|
|
@@ -157,16 +152,13 @@ coordinateValidator.isValid([10, 20, 30]) // false (wrong length)
|
|
|
157
152
|
```typescript
|
|
158
153
|
import { record, recordValues, string, number } from '@amazon/vinyl-validation'
|
|
159
154
|
|
|
160
|
-
// Record with string keys and number values
|
|
161
155
|
const scoresValidator = recordValues(number().gte(0))
|
|
162
156
|
|
|
163
|
-
// Record with specific key and value types
|
|
164
157
|
const configValidator = record(
|
|
165
|
-
string().matches(/^[A-Z_]+$/),
|
|
166
|
-
string().notEmpty()
|
|
158
|
+
string().matches(/^[A-Z_]+$/),
|
|
159
|
+
string().notEmpty()
|
|
167
160
|
)
|
|
168
161
|
|
|
169
|
-
// Usage
|
|
170
162
|
scoresValidator.isValid({ alice: 95, bob: 87 }) // true
|
|
171
163
|
configValidator.isValid({ API_KEY: 'secret', DB_URL: 'localhost' }) // true
|
|
172
164
|
```
|
|
@@ -178,7 +170,6 @@ import { set, string } from '@amazon/vinyl-validation'
|
|
|
178
170
|
|
|
179
171
|
const tagValidator = set(string().notEmpty())
|
|
180
172
|
|
|
181
|
-
// Usage
|
|
182
173
|
tagValidator.isValid(new Set(['tag1', 'tag2'])) // true
|
|
183
174
|
tagValidator.isValid(new Set(['tag1', ''])) // false (empty string)
|
|
184
175
|
```
|
|
@@ -188,12 +179,8 @@ tagValidator.isValid(new Set(['tag1', ''])) // false (empty string)
|
|
|
188
179
|
```typescript
|
|
189
180
|
import { func } from '@amazon/vinyl-validation'
|
|
190
181
|
|
|
191
|
-
const functionValidator = func()
|
|
192
|
-
.withArity(2) // exactly 2 parameters
|
|
193
|
-
.withMinArity(1) // at least 1 parameter
|
|
194
|
-
.withMaxArity(3) // at most 3 parameters
|
|
182
|
+
const functionValidator = func().withArity(2).withMinArity(1).withMaxArity(3)
|
|
195
183
|
|
|
196
|
-
// Usage
|
|
197
184
|
functionValidator.isValid((a, b) => a + b) // true
|
|
198
185
|
functionValidator.isValid(() => 'hello') // false (wrong arity)
|
|
199
186
|
```
|
|
@@ -201,18 +188,12 @@ functionValidator.isValid(() => 'hello') // false (wrong arity)
|
|
|
201
188
|
## Optional and Nullable Values
|
|
202
189
|
|
|
203
190
|
```typescript
|
|
204
|
-
import { string
|
|
205
|
-
|
|
206
|
-
// Optional (allows undefined)
|
|
207
|
-
const optionalName = string().optional()
|
|
208
|
-
|
|
209
|
-
// Nullable (allows null)
|
|
210
|
-
const nullableName = string().nullable()
|
|
191
|
+
import { string } from '@amazon/vinyl-validation'
|
|
211
192
|
|
|
212
|
-
|
|
213
|
-
const
|
|
193
|
+
const optionalName = string().optional() // allows undefined
|
|
194
|
+
const nullableName = string().nullable() // allows null
|
|
195
|
+
const maybeName = string().maybe() // allows null or undefined
|
|
214
196
|
|
|
215
|
-
// Usage
|
|
216
197
|
optionalName.isValid(undefined) // true
|
|
217
198
|
nullableName.isValid(null) // true
|
|
218
199
|
maybeName.isValid(null) // true
|
|
@@ -224,9 +205,9 @@ maybeName.isValid(undefined) // true
|
|
|
224
205
|
### OR Logic
|
|
225
206
|
|
|
226
207
|
```typescript
|
|
227
|
-
import {
|
|
208
|
+
import { orValidators, string, number } from '@amazon/vinyl-validation'
|
|
228
209
|
|
|
229
|
-
const stringOrNumber =
|
|
210
|
+
const stringOrNumber = orValidators(string(), number())
|
|
230
211
|
|
|
231
212
|
stringOrNumber.isValid('hello') // true
|
|
232
213
|
stringOrNumber.isValid(42) // true
|
|
@@ -236,9 +217,9 @@ stringOrNumber.isValid(true) // false
|
|
|
236
217
|
### AND Logic
|
|
237
218
|
|
|
238
219
|
```typescript
|
|
239
|
-
import {
|
|
220
|
+
import { andValidators, string } from '@amazon/vinyl-validation'
|
|
240
221
|
|
|
241
|
-
const shortUppercaseString =
|
|
222
|
+
const shortUppercaseString = andValidators(
|
|
242
223
|
string().maxLength(10),
|
|
243
224
|
string().matches(/^[A-Z]+$/)
|
|
244
225
|
)
|
|
@@ -258,14 +239,6 @@ const evenNumberValidator = custom<number>(
|
|
|
258
239
|
(input): input is number => typeof input === 'number' && input % 2 === 0
|
|
259
240
|
)
|
|
260
241
|
|
|
261
|
-
// With custom stringify function
|
|
262
|
-
const positiveValidator = custom<number>(
|
|
263
|
-
'positive number',
|
|
264
|
-
(input): input is number => typeof input === 'number' && input > 0,
|
|
265
|
-
(input) => `number: ${input}`
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
// Usage
|
|
269
242
|
evenNumberValidator.isValid(4) // true
|
|
270
243
|
evenNumberValidator.isValid(3) // false
|
|
271
244
|
```
|
|
@@ -282,12 +255,6 @@ const validator = object({
|
|
|
282
255
|
|
|
283
256
|
// Collect all errors (default: stop at first error)
|
|
284
257
|
const errors = validator.validate({ name: '', email: 'invalid' }, { all: true })
|
|
285
|
-
|
|
286
|
-
console.log(errors)
|
|
287
|
-
// [
|
|
288
|
-
// { message: 'Expected: not empty, but was: "". At: name', path: ['name'] },
|
|
289
|
-
// { message: 'Expected: matches /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/, but was: "invalid". At: email', path: ['email'] }
|
|
290
|
-
// ]
|
|
291
258
|
```
|
|
292
259
|
|
|
293
260
|
## Error Handling
|
|
@@ -302,43 +269,35 @@ try {
|
|
|
302
269
|
validator.assert('') // throws ValidationError if invalid
|
|
303
270
|
} catch (error) {
|
|
304
271
|
if (error instanceof ValidationError) {
|
|
305
|
-
console.log(error.message)
|
|
272
|
+
console.log(error.message)
|
|
306
273
|
}
|
|
307
274
|
}
|
|
308
|
-
|
|
309
|
-
// Or use validate() for non-throwing validation
|
|
310
|
-
const errors = validator.validate('')
|
|
311
|
-
if (errors.length > 0) {
|
|
312
|
-
console.log('Validation failed:', errors)
|
|
313
|
-
}
|
|
314
275
|
```
|
|
315
276
|
|
|
316
277
|
## TypeScript Integration
|
|
317
278
|
|
|
318
|
-
The idiomatic usage is to start with an interface and create a schema for it:
|
|
319
|
-
|
|
320
279
|
```typescript
|
|
321
280
|
import { object, string, number, array } from '@amazon/vinyl-validation'
|
|
322
281
|
|
|
323
|
-
// Define your interface first
|
|
324
282
|
interface User {
|
|
325
283
|
name: string
|
|
326
284
|
age?: number
|
|
327
285
|
tags: string[]
|
|
328
286
|
}
|
|
329
287
|
|
|
330
|
-
// Create a validator that matches the interface
|
|
331
288
|
const userValidator = object<User>({
|
|
332
289
|
name: string(),
|
|
333
290
|
age: number().optional(),
|
|
334
291
|
tags: array(string()),
|
|
335
292
|
})
|
|
336
293
|
|
|
337
|
-
// Type-safe validation
|
|
338
294
|
function processUser(data: unknown) {
|
|
339
295
|
if (userValidator.isValid(data)) {
|
|
340
|
-
|
|
341
|
-
console.log(data.name) // TypeScript knows this is a string
|
|
296
|
+
console.log(data.name) // typed as string
|
|
342
297
|
}
|
|
343
298
|
}
|
|
344
299
|
```
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
Apache-2.0
|
package/dist/index.cjs
CHANGED
|
@@ -253,9 +253,9 @@ var requiredValidationOptions = {
|
|
|
253
253
|
};
|
|
254
254
|
var SchemaBase = class {
|
|
255
255
|
constructor(currentValidator, previousSchema, operation) {
|
|
256
|
-
this
|
|
257
|
-
this
|
|
258
|
-
this
|
|
256
|
+
__publicField(this, "currentValidator", currentValidator);
|
|
257
|
+
__publicField(this, "previousSchema", previousSchema);
|
|
258
|
+
__publicField(this, "operation", operation);
|
|
259
259
|
__publicField(this, "__type", /* @__PURE__ */ (0, import_vinyl_util5.invariant)());
|
|
260
260
|
__publicField(this, "validator");
|
|
261
261
|
__publicField(this, "_options", requiredValidationOptions);
|