vuelidify 1.0.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/LICENSE +21 -0
- package/README.md +378 -0
- package/dist/index.d.ts +251 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/favicon.ico +0 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Daniel Walbolt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# Vuelidify
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[Installation](#installation)
|
|
5
|
+
[Types](#types)
|
|
6
|
+
[Examples](#examples)
|
|
7
|
+
---
|
|
8
|
+
*A simple and lightweight Vue 3 model based validation library with strong type support.*
|
|
9
|
+
|
|
10
|
+
This library was inspired by Vuelidate but seeks to solve some of its biggest problems. This library does NOT support Vue2, and does NOT support commonJS. Technology must move forward.
|
|
11
|
+
|
|
12
|
+
**✨ Simple** because it does exactly what it needs to with no dependencies other than Vue.
|
|
13
|
+
|
|
14
|
+
**🪶 Lightweight** because the .mjs is <9KB (uncompressed), and ~3KB gzipped.
|
|
15
|
+
|
|
16
|
+
**📝 Model based** refers to validation being done in the script tag on an object. This is an alternative to template based validation, which uses template components and attributes to validate an object.
|
|
17
|
+
|
|
18
|
+
**💪 Strong types** makes setting up validation intuitive for developers. No more: "wait, how do I do that again?"
|
|
19
|
+
|
|
20
|
+
Too many validation libraries for Vue lack good type support; which negatively impacts maintainability. Changes to models would not indicate that validation needs to be updated as well. This library was created to fix that problem.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm i vuelidify
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
yarn add vuelidify
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
pnpm add vuelidify
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Types
|
|
39
|
+
|
|
40
|
+
This was created for use in ```<script setup lang="ts">```, meaning you need TypeScript in order to get the full benefits of this library.
|
|
41
|
+
|
|
42
|
+
**useValidation()** is the starting point for validating your models.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { useValidation } from "vuelidify";
|
|
47
|
+
|
|
48
|
+
// The starting point for validation
|
|
49
|
+
const v$ = useValidation({});
|
|
50
|
+
</script>
|
|
51
|
+
```
|
|
52
|
+
Here is a breakdown of the configuration object the composable expects.
|
|
53
|
+
```ts
|
|
54
|
+
{
|
|
55
|
+
objectToValidate: T, // The ref, computed, or reactive object you want to validate.
|
|
56
|
+
validation: Validation<T>, // Describes how to validate your object.
|
|
57
|
+
args: A = undefined, // Can be anything! Will be passed into every validator.
|
|
58
|
+
delayReactiveValidation: boolean, // Should reactive validation be active immediately or only after calling validate()?
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
That's it, super simple!
|
|
62
|
+
|
|
63
|
+
Just kidding, ```validation: Validation<T>``` isn't the full picture. The type here is quite complicated, but easy to use. Here's what you need to know.
|
|
64
|
+
|
|
65
|
+
1. ```Validation<T>``` will copy the type of your object, down to the names of properties. Nested objects will also be copied, and their inner types as well. This type is recursive!
|
|
66
|
+
2. Properties which are primitives or arrays are the exit conditions to the recursive type. Instead they will present ```PrimitiveValidationTypes``` or ```ArrayValidationTypes``` respectively.
|
|
67
|
+
```ts
|
|
68
|
+
{
|
|
69
|
+
// foo is a string
|
|
70
|
+
foo: {
|
|
71
|
+
$reactive?: [],
|
|
72
|
+
$lazy?: []
|
|
73
|
+
}
|
|
74
|
+
// bar is an array
|
|
75
|
+
bar: {
|
|
76
|
+
$each?: {},
|
|
77
|
+
$reactive?: [],
|
|
78
|
+
$lazy?: []
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
3. Arrays are special. If you have an array of objects that need validated, ```$each``` will be your friend. ```$each``` will be the same type as ```Validation<U>``` where ```U``` is the type of each object in the array. This loop can go on forever, as long as your object also has sufficiently many children and arrays!
|
|
83
|
+
4. ```$reactive``` is an array of validators that should be performed on that property reactively.
|
|
84
|
+
5. ```$lazy``` is an array of validators that should be performed on that property whenever ```validate()``` is called. This was added so you can control when more expensive validatiors are invoked.
|
|
85
|
+
|
|
86
|
+
Here is the breakdown of the return of the composable
|
|
87
|
+
```ts
|
|
88
|
+
{
|
|
89
|
+
hasValidated: boolean,
|
|
90
|
+
// True if you object has changed from the reference.
|
|
91
|
+
// Useful for enabling save buttons after changes have been made
|
|
92
|
+
isDirty: boolean,
|
|
93
|
+
isValid: boolean,
|
|
94
|
+
isValidating: boolean,
|
|
95
|
+
// Access the results of validation. This will copy the properties of your object.
|
|
96
|
+
// Every "exit" condition have it's own type explained below
|
|
97
|
+
state: ValidationState<T>,
|
|
98
|
+
// Set the comparison object for determining dirty state.
|
|
99
|
+
// If your object must first load in asynchronously,
|
|
100
|
+
// use this function to set the reference once it has loaded.
|
|
101
|
+
setReference: (reference: T) => void,
|
|
102
|
+
validate: () => Promise<boolean>
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
Here is the breakdown of the validation state
|
|
106
|
+
```ts
|
|
107
|
+
{
|
|
108
|
+
// The collected error messages returned from all the validators
|
|
109
|
+
errorMessages: string[],
|
|
110
|
+
// True if any validators returned false.
|
|
111
|
+
// Not equivalent to !isValid, because !isValid is true even
|
|
112
|
+
// when validation has not been ran yet.
|
|
113
|
+
// Can be false when there are lazy validators that still need executed.
|
|
114
|
+
isErrored: boolean,
|
|
115
|
+
// True if the last run of lazy and reactive validators all passed.
|
|
116
|
+
isValid: boolean,
|
|
117
|
+
isValidating: boolean,
|
|
118
|
+
// A map for easily accessing named validation results.
|
|
119
|
+
// This is the one spot without type support
|
|
120
|
+
results: { [key: string]: BaseValidationReturn<F> }
|
|
121
|
+
// A 2D array of the validation results
|
|
122
|
+
resultsArray: Array<BaseValidationReturn<F>>
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
Here is the breakdown of the return type from validators.
|
|
126
|
+
```ts
|
|
127
|
+
// Validators must either return a BaseValidationReturn<F> object, undefined,
|
|
128
|
+
// or an array of validators which will be invoked immediately.
|
|
129
|
+
{
|
|
130
|
+
// Name the result of this validator. This will put the validation result
|
|
131
|
+
// into the results map in the validation state of this property.
|
|
132
|
+
// Make sure your names are unique between your validators.
|
|
133
|
+
name?: string,
|
|
134
|
+
// the unique identifier for this validation result. Assigned interally.
|
|
135
|
+
// you can use this ID to identify your DOM elements that display error messages.
|
|
136
|
+
id? string,
|
|
137
|
+
// required for determining whether or not this validator passed
|
|
138
|
+
isValid: boolean,
|
|
139
|
+
errorMessage?: string,
|
|
140
|
+
// Sometimes a true or false is not enough information for end users.
|
|
141
|
+
// Use this to return any object to give additional information about the validation.
|
|
142
|
+
// In order to access this custom data easily, make sure you give the result a name
|
|
143
|
+
custom?: F,
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
Here is the breakdown of the parameters that are passed into validators
|
|
147
|
+
```ts
|
|
148
|
+
{
|
|
149
|
+
// The value of the property being validated
|
|
150
|
+
value: T,
|
|
151
|
+
// The top-most ancestor being validated. The object that was passed to the composable.
|
|
152
|
+
parent: P,
|
|
153
|
+
// The args that were specified in the composable configuration.
|
|
154
|
+
// This type will only appear for you when args is NOT undefined.
|
|
155
|
+
args: V,
|
|
156
|
+
// Will only appear for properties nested in some array.
|
|
157
|
+
// The type will be an ordered array of strongly typed objects.
|
|
158
|
+
// Each element is a "parent" in the array, or an ancestor to the property you're validating.
|
|
159
|
+
// Index 0 will be appear when you're 1 array deep, and index 1 will appear 2 arrays deep, etc.
|
|
160
|
+
// The limit of nested arrays is currently 20, and I don't think you'll need more than that.
|
|
161
|
+
// Extremely useful for complex validation of arrays where validation depends on the array object,
|
|
162
|
+
// rather than the top-most parent object which contains the array.
|
|
163
|
+
arrayParents: A
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Examples
|
|
168
|
+
#### Primitives
|
|
169
|
+
```ts
|
|
170
|
+
<script setup lang="ts">
|
|
171
|
+
import { ref } from 'vue';
|
|
172
|
+
import { minLength, useValidation } from "vuelidify";
|
|
173
|
+
|
|
174
|
+
const string = ref("");
|
|
175
|
+
const v$ = useValidation({
|
|
176
|
+
objectToValidate: string,
|
|
177
|
+
validation: {
|
|
178
|
+
$reactive: [minLength(10)] // Put as many validators as you want here
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
</script>
|
|
182
|
+
```
|
|
183
|
+
#### Simple Objects
|
|
184
|
+
```ts
|
|
185
|
+
<script setup lang="ts">
|
|
186
|
+
import { ref } from 'vue';
|
|
187
|
+
import { minLength, useValidation, minNumber } from "vuelidify";
|
|
188
|
+
|
|
189
|
+
const obj = ref({
|
|
190
|
+
foo: "string",
|
|
191
|
+
bar: true,
|
|
192
|
+
zaa: 1
|
|
193
|
+
});
|
|
194
|
+
const v$ = useValidation({
|
|
195
|
+
objectToValidate: obj,
|
|
196
|
+
validation: {
|
|
197
|
+
foo: {
|
|
198
|
+
// Validate foo when v$.validate is called.
|
|
199
|
+
$lazy: [minLength(10)]
|
|
200
|
+
},
|
|
201
|
+
bar: {
|
|
202
|
+
// Validate bar reactively
|
|
203
|
+
$reactive: [(params) => {
|
|
204
|
+
return {
|
|
205
|
+
isValid: params.value
|
|
206
|
+
}
|
|
207
|
+
}]
|
|
208
|
+
},
|
|
209
|
+
zaa: {
|
|
210
|
+
// Validate zaa reactively and when v$.validate is called.
|
|
211
|
+
// Notice how validation can depend on other properties in the parent.
|
|
212
|
+
$reactive: [minNumber(10)],
|
|
213
|
+
$lazy: [
|
|
214
|
+
(params) => {
|
|
215
|
+
const isBar = params.parent.bar;
|
|
216
|
+
return {
|
|
217
|
+
isValid: isBar ? params.value > 100 : true,
|
|
218
|
+
errorMessage: "Must be greater than 100 when bar is true"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
</script>
|
|
226
|
+
```
|
|
227
|
+
#### Arrays
|
|
228
|
+
```ts
|
|
229
|
+
<script setup lang="ts">
|
|
230
|
+
import { ref } from 'vue';
|
|
231
|
+
import { minLength, useValidation } from "vuelidify";
|
|
232
|
+
|
|
233
|
+
type FooBar = {
|
|
234
|
+
name: string;
|
|
235
|
+
isActive: boolean;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const array = ref<FooBar[]>([]);
|
|
239
|
+
const v$ = useValidation({
|
|
240
|
+
objectToValidate: array,
|
|
241
|
+
validation: {
|
|
242
|
+
// Validate each object in the array.
|
|
243
|
+
$each: {
|
|
244
|
+
name: {
|
|
245
|
+
// Reactively validate every name
|
|
246
|
+
$reactive: [
|
|
247
|
+
// Validate the length of the name only if the object's isActive property is true.
|
|
248
|
+
(params) => {
|
|
249
|
+
if (params.arrayParents[0].isActive !== true) {
|
|
250
|
+
// Return undefined to ignore this validator when the condition is not true.
|
|
251
|
+
// This check can even be asynchronous!
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
return [minLength(10)]
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
</script>
|
|
262
|
+
```
|
|
263
|
+
#### Complex Objects
|
|
264
|
+
Sometimes your objects will contain other objects and arrays.
|
|
265
|
+
```ts
|
|
266
|
+
<script setup lang="ts">
|
|
267
|
+
import { ref } from 'vue';
|
|
268
|
+
import { minLength, minNumber, useValidation } from "vuelidify";
|
|
269
|
+
|
|
270
|
+
type Person = {
|
|
271
|
+
a: Person,
|
|
272
|
+
b: Person[]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
type Person = {
|
|
276
|
+
name: string;
|
|
277
|
+
age: number;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const complexObj = ref<Person>();
|
|
281
|
+
const v$ = useValidation({
|
|
282
|
+
objectToValidate: complexObj,
|
|
283
|
+
validation: {
|
|
284
|
+
a: {
|
|
285
|
+
// Validate person a's age reactively
|
|
286
|
+
age: {
|
|
287
|
+
$reactive: [minNumber(16)]
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
b: {
|
|
291
|
+
// Validate each person in b
|
|
292
|
+
$each: {
|
|
293
|
+
// Validate age reactively and lazily
|
|
294
|
+
age: {
|
|
295
|
+
$reactive: [
|
|
296
|
+
// Make sure each person in the array is younger than person a
|
|
297
|
+
(params) => {
|
|
298
|
+
return {
|
|
299
|
+
isValid: params.value < params.parent.a.age,
|
|
300
|
+
errorMessage: "Must be younger than person a."
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
$lazy: [minNumber(15)]
|
|
305
|
+
},
|
|
306
|
+
name: {
|
|
307
|
+
$reactive: [minLength(10)]
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
</script>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Technical Details
|
|
317
|
+
For those interested in the inner workings of the library without looking at the code:
|
|
318
|
+
|
|
319
|
+
- Reactive validation is performed by a deep watcher on the parent object. This was done because of inter-property dependence. When a validator for one property relies on another property in the object, it needs to be reevaluated. This does come with the technical debt of running every *reactive* validator in your object every time the user enters a character. But I this is mediated by validator optimizations discussed later.
|
|
320
|
+
- Lazy validation is only performed only when the validate() function is called. However, validate() will also invoke all reactive validators to guarantee all validation results are up-to-date with the model. Properties or the object itself may be valid before ever calling validate() if there were no lazy validators specified, and all reactive validators were true (or again none specified).
|
|
321
|
+
- Async validators can be mixed with sync validators, so there is no way to distinguish them upon initialization. However, once they are invoked for the first time, it is possible to distinguish them. Optimizations can then be made on the sync and async validators to improve validation behavior and performance. Sync validators will be wrapped in a computed function which has the benefit of determining reactive dependencies and caching the result. This counteracts the downside of using a deep watcher discussed previously. Synchronous validators will not be needlessly reevaluated every time a character changes in an unrelated property because the computed determines it doesn't rely on it. Async validators will be optimized based on how long they take to return. If they return faster than 250ms, they will not be given any optimization; if they return less than 500ms they will be given a throttle of 250ms; if they return longer than that they will be given a buffer. Details of the throttles are below.
|
|
322
|
+
- ```throttleQueueAsync``` is a custom function exported by this library which solves some of the problems I had with lodash's throttle function. This function throttles a function, can copy it's signature, and returns a promise for the result of the function. Calling this function will instantly execute the function if there is no active throttle. Calling this function with an active throttle will return a promise to call the function as soon as the throttle has expired. Calling the function multiple times during the throttle period will keep overriding the queued promise. Overridden queued promises will return undefined once the throttle expires. This function is very complicated, but extremely useful for returning control back to the caller and guaranteeing that the function gets called with the latest parameters. This are all problems with current implementation of debounce or throttle which use setTimeout() without being wrapped in a promise.
|
|
323
|
+
- ```bufferAsync``` is another custom function exported by this library which offers a more aggressive throttling behavior than ```throttleQueueAsync```. Instead, this function creates an "invocation buffer" on the provided function, copies the functions signature, and returns a promise to the result of the function. Essentially, the function provided will only be ran once the previous invocation of the function has returned. This function also uses a queue to guarantee invocation of the desired function after the previous invocation has returned.
|
|
324
|
+
|
|
325
|
+
# Create your own validators
|
|
326
|
+
There aren't many validators provided by this library on purpose. Mostly because I didn't want to think of what could be useful, and would rather rely on feedback for useful validators. Feel free to give me feedback on the github repo.
|
|
327
|
+
|
|
328
|
+
I highly encourage you to understand the types enough to create your own validators. It isn't too difficult, and you should be able to base it off some of the existing ones.
|
|
329
|
+
|
|
330
|
+
Here is a breakdown of one of the validators exported by this library (expanded to make comments more readable):
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
// always provide a header comment to explain what the validator does!
|
|
334
|
+
/**
|
|
335
|
+
* Checks if the string value is a valid looking email using RegEx.
|
|
336
|
+
*
|
|
337
|
+
* The RegEx was taken from https://stackoverflow.com/questions/46155/how-can-i-validate-an-email-address-in-javascript, and may be updated in the future.
|
|
338
|
+
* @returns Synchronous validator
|
|
339
|
+
*/
|
|
340
|
+
export function isEmailSync<
|
|
341
|
+
// The type of the property you want to support validation for.
|
|
342
|
+
// adding | undefined | null is good practice for writing more robust code
|
|
343
|
+
// Furthermore, if you just did string here, it wouldn't work with string?
|
|
344
|
+
T extends string | undefined | null,
|
|
345
|
+
// The type for the parent object.
|
|
346
|
+
// Generally you don't put constraints on this.
|
|
347
|
+
P,
|
|
348
|
+
// The type for the args
|
|
349
|
+
// You may want to put a constraint on this if you need access to a store, or some other external data.
|
|
350
|
+
V,
|
|
351
|
+
// The type for the custom return from the validator
|
|
352
|
+
R,
|
|
353
|
+
// The type for the arrayParents parameter.
|
|
354
|
+
// Generally you don't put constraints on this.
|
|
355
|
+
// But you have to accept this generic in order to pass the type forward to not mess up outside types.
|
|
356
|
+
A
|
|
357
|
+
>(
|
|
358
|
+
// Specify any parameters you need here. They could be Refs, primitives, whatever!
|
|
359
|
+
): SyncValidator<T, P, V, R, A> // Strongly type the type of validator you'll be returning
|
|
360
|
+
{
|
|
361
|
+
// Return a validator function
|
|
362
|
+
return (
|
|
363
|
+
// Strongly type the expected params object to have intellisense
|
|
364
|
+
params: ValidatorParams<T, P, V, A>
|
|
365
|
+
) => {
|
|
366
|
+
// you can do whatever you want a normal validator can in here.
|
|
367
|
+
// Return undefined, an array of validators, or a validation result.
|
|
368
|
+
// In this case, we're checking the value of the property against an email regex.
|
|
369
|
+
return {
|
|
370
|
+
isValid: params.value ? RegExp(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(params.value) : false,
|
|
371
|
+
errorMessage: "Invalid email format"
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
The type system that makes all this possible is fairly fragile. These problems may well be a limitation of TypeScript rather than of this package.
|
|
378
|
+
I have encountered such problems when trying to build certain generic custom validators. Feel free to post issues you may have with the package on the git repo!
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
/** Shorthand union of the primitive types */
|
|
4
|
+
type Primitive = string | number | boolean;
|
|
5
|
+
/** Holds the latest results of validation for an object */
|
|
6
|
+
type ValidationState<T, FValidationReturn> = T extends Array<infer U> ? ArrayValidationState<U, FValidationReturn> : T extends IndexableObject ? RecursiveValidationState<T, FValidationReturn> : T extends Primitive ? PrimitiveValidationState<FValidationReturn> : undefined;
|
|
7
|
+
type RecursiveValidationState<T, FValidationReturn> = {
|
|
8
|
+
[key in keyof T]?: ValidationState<T[key], FValidationReturn>;
|
|
9
|
+
};
|
|
10
|
+
/** Contains the reactive state of validation for a property. */
|
|
11
|
+
type PrimitiveValidationState<FValidationReturn> = {
|
|
12
|
+
/** True if all the validators defined for this property have passed. False otherwise. */
|
|
13
|
+
isValid: boolean;
|
|
14
|
+
isValidating: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* True if there are any results that failed validation.
|
|
17
|
+
*
|
|
18
|
+
* Not quite the complement of {@link isValid} because !{@link isValid} can be true when no validators have been called yet.
|
|
19
|
+
* This will only ever be true when validation results have returned.
|
|
20
|
+
*/
|
|
21
|
+
isErrored: boolean;
|
|
22
|
+
/** Easy collection of the error messages from the raw validation returns */
|
|
23
|
+
errorMessages: string[];
|
|
24
|
+
results: {
|
|
25
|
+
[key: string]: BaseValidationReturn<FValidationReturn>;
|
|
26
|
+
};
|
|
27
|
+
resultsArray: BaseValidationReturn<FValidationReturn>[];
|
|
28
|
+
};
|
|
29
|
+
type ArrayValidationState<U, FValidationReturn> = PrimitiveValidationState<FValidationReturn> & {
|
|
30
|
+
/**
|
|
31
|
+
* Contains the validation state for each element in the array.
|
|
32
|
+
*
|
|
33
|
+
* Maps 1:1 to the array which was validated.
|
|
34
|
+
*/
|
|
35
|
+
arrayState: ValidationState<U, FValidationReturn>[];
|
|
36
|
+
};
|
|
37
|
+
type RecursiveValidation<T extends IndexableObject, KParent, ValidationArgs, FValidationReturn, ArrParent, NLevel extends number> = {
|
|
38
|
+
[key in keyof Partial<T>]: Validation<T[key], ValidationArgs, FValidationReturn, KParent, ArrParent, NLevel>;
|
|
39
|
+
};
|
|
40
|
+
type PrimitiveValidation<T extends Primitive | undefined | null, KParent, Args, FValidationReturn, ArrParent> = PrimitiveValidatorTypes<T, KParent, Args, FValidationReturn, ArrParent>;
|
|
41
|
+
type IndexableObject = {
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
};
|
|
44
|
+
/** Separates the reactive and lazy validators of a primitive property. */
|
|
45
|
+
type PrimitiveValidatorTypes<T, KParent, Args, FValidationReturn, ArrParent> = {
|
|
46
|
+
/** The validators for this property that are invoked whenever the form is changed. */
|
|
47
|
+
$reactive?: Validator<T, KParent, Args, FValidationReturn, ArrParent>[];
|
|
48
|
+
/** The validators for this property that are invoked only after {@link validate()} is invoked. */
|
|
49
|
+
$lazy?: Validator<T, KParent, Args, FValidationReturn, ArrParent>[];
|
|
50
|
+
};
|
|
51
|
+
type ArrayValidatorTypes<U, T extends Array<U>, KParent, Args, FValidationReturn, ArrParent, NLevel extends number> = {
|
|
52
|
+
/**
|
|
53
|
+
* Can only be used with object arrays. Not string, number, or boolean (primitive) arrays.
|
|
54
|
+
*
|
|
55
|
+
* Defines the validation that should be performed on each element of the array.
|
|
56
|
+
*
|
|
57
|
+
* Element validation requires much more logic, which may introduce performance problems for large arrays.
|
|
58
|
+
*/
|
|
59
|
+
$each?: Validation<U, Args, FValidationReturn, KParent, ArrParent extends undefined ? Array<any> & {
|
|
60
|
+
[key in NLevel]: U;
|
|
61
|
+
} : ArrParent & {
|
|
62
|
+
[key in NLevel]: U;
|
|
63
|
+
}, Increment<NLevel>>;
|
|
64
|
+
/** The validators for the array that are invoked whenever the form is changed. */
|
|
65
|
+
$reactive?: Validator<T, KParent, Args, FValidationReturn, ArrParent>[];
|
|
66
|
+
/** The validators for the array that are invoked only when {@link validate()} is called. */
|
|
67
|
+
$lazy?: Validator<T, KParent, Args, FValidationReturn, ArrParent>[];
|
|
68
|
+
};
|
|
69
|
+
/** A synchronous or asynchronous validator. */
|
|
70
|
+
type Validator<T, KParent, Args, FValidationReturn, ArrParent> = (SyncValidator<T, KParent, Args, FValidationReturn, ArrParent> | AsyncValidator<T, KParent, Args, FValidationReturn, ArrParent>);
|
|
71
|
+
type ValidatorTypes<T, KParent, Args, FValidationReturn, ArrParent, NLevel extends number> = T extends Array<infer U> ? ArrayValidatorTypes<U, T, KParent, Args, FValidationReturn, ArrParent, NLevel> : PrimitiveValidatorTypes<T, KParent, Args, FValidationReturn, ArrParent>;
|
|
72
|
+
type BaseValidator<T, Parent, Args, Return, ArrParent> = (input: ValidatorParams<T, Parent, Args, ArrParent>) => Return;
|
|
73
|
+
type SyncValidator<T, Parent, Args, Return, ArrParent> = BaseValidator<T, Parent, Args, BaseValidationReturn<Return> | Array<Validator<T, Parent, Args, Return, ArrParent>> | undefined, ArrParent>;
|
|
74
|
+
type AsyncValidator<T, Parent, Args, Return, ArrParent> = BaseValidator<T, Parent, Args, Promise<BaseValidationReturn<Return> | Array<Validator<T, Parent, Args, Return, ArrParent>> | undefined>, ArrParent>;
|
|
75
|
+
type BaseValidationReturn<F = any> = {
|
|
76
|
+
/**
|
|
77
|
+
* Assign this validator's result a name.
|
|
78
|
+
* The result will then be added to a map using the name as the key
|
|
79
|
+
* so you can easily access the result.
|
|
80
|
+
*
|
|
81
|
+
* Note, the map entry will not exist until this validator has been run at least once, so account for undefined.
|
|
82
|
+
*/
|
|
83
|
+
name?: string;
|
|
84
|
+
/**
|
|
85
|
+
* The unique identifier for this validation result.
|
|
86
|
+
*
|
|
87
|
+
* Assigned and used internally, but can be used as your element's ID or key attribute.
|
|
88
|
+
*/
|
|
89
|
+
id?: string;
|
|
90
|
+
/** Used to determine if validation was successful or not. */
|
|
91
|
+
isValid: boolean;
|
|
92
|
+
/** The message or messages to display if isValid is false. */
|
|
93
|
+
errorMessage?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Return a custom object from this validator.
|
|
96
|
+
*
|
|
97
|
+
* Should be used for more sophisticated return types than a boolean.
|
|
98
|
+
*
|
|
99
|
+
* i.e. password strength, severity levels, functions, etc.
|
|
100
|
+
*/
|
|
101
|
+
custom?: F;
|
|
102
|
+
};
|
|
103
|
+
type ArrayValidationReturn<U, FValidationReturn> = BaseValidationReturn<FValidationReturn> & {
|
|
104
|
+
/** The raw list of results from validating every object in the array. */
|
|
105
|
+
arrayResults?: ValidationState<U, FValidationReturn>[];
|
|
106
|
+
};
|
|
107
|
+
type Validation<T, Args = undefined, FValidationReturn = undefined, KParent = T, ArrParent = undefined, NLevel extends number = 0> = T extends Array<infer U> ? ArrayValidatorTypes<U, T, KParent, Args, FValidationReturn, ArrParent, NLevel> : T extends IndexableObject ? RecursiveValidation<T, KParent, Args, FValidationReturn, ArrParent, NLevel> : T extends boolean ? PrimitiveValidation<boolean | undefined | null, KParent | undefined | null, Args, FValidationReturn, ArrParent> : T extends Primitive ? PrimitiveValidation<T | undefined | null, KParent | undefined | null, Args, FValidationReturn, ArrParent> : undefined;
|
|
108
|
+
type ValidationConfig<T, Args, FValidationReturn> = {
|
|
109
|
+
/**
|
|
110
|
+
* If the object you provided is not in a good state (i.e. it must be loaded in asynchronously first),
|
|
111
|
+
* call the {@link setup()} method returned by this composable after it has loaded.
|
|
112
|
+
*
|
|
113
|
+
* Setting up validation on an incomplete object will mean that the properties of the object
|
|
114
|
+
* can not be linked to the validation configured, thus causing problems.
|
|
115
|
+
*/
|
|
116
|
+
objectToValidate: Ref<T | undefined | null>;
|
|
117
|
+
validation: Validation<T, Args, FValidationReturn, T>;
|
|
118
|
+
/**
|
|
119
|
+
* False - reactive validation will always be active.
|
|
120
|
+
*
|
|
121
|
+
* True - reactive validation will start after the first invocation of {@link validate()}.
|
|
122
|
+
*
|
|
123
|
+
* Defaults to true.
|
|
124
|
+
*/
|
|
125
|
+
delayReactiveValidation?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Provide an object, ref, or function that will be passed to each validator.
|
|
128
|
+
* Particularly useful when defining validation in separate files and you want to use variables outside of the object being validated.
|
|
129
|
+
*/
|
|
130
|
+
args?: Args;
|
|
131
|
+
};
|
|
132
|
+
/** Describes the parameter passed into validator functions */
|
|
133
|
+
type ValidatorParams<T, KParent, Args, ArrParent> = {
|
|
134
|
+
/** The current value of the property */
|
|
135
|
+
value: T;
|
|
136
|
+
/** The entire object that was passed into the useValidation() composable to be validated. */
|
|
137
|
+
parent: KParent;
|
|
138
|
+
} & (Args extends undefined ? unknown : {
|
|
139
|
+
/** The args passed in to the useValidation() composable configuration. */
|
|
140
|
+
args: Args;
|
|
141
|
+
}) & (ArrParent extends undefined ? unknown : {
|
|
142
|
+
/**
|
|
143
|
+
* An ordered list of objects that were traversed through while navigating to this validator.
|
|
144
|
+
*
|
|
145
|
+
* Each nested array will add 1 entry to this list. Each entry will be strongly-typed to the element of its respective array.
|
|
146
|
+
*
|
|
147
|
+
* Useful for inter-property dependence when validating arrays of complex objects.
|
|
148
|
+
*/
|
|
149
|
+
arrayParents: ArrParent;
|
|
150
|
+
});
|
|
151
|
+
/** Type that increments a provided integer (0-19). */
|
|
152
|
+
type Increment<N extends number> = [
|
|
153
|
+
1,
|
|
154
|
+
2,
|
|
155
|
+
3,
|
|
156
|
+
4,
|
|
157
|
+
5,
|
|
158
|
+
6,
|
|
159
|
+
7,
|
|
160
|
+
8,
|
|
161
|
+
9,
|
|
162
|
+
10,
|
|
163
|
+
11,
|
|
164
|
+
12,
|
|
165
|
+
13,
|
|
166
|
+
14,
|
|
167
|
+
15,
|
|
168
|
+
16,
|
|
169
|
+
17,
|
|
170
|
+
18,
|
|
171
|
+
19,
|
|
172
|
+
20,
|
|
173
|
+
...number[]
|
|
174
|
+
][N];
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Returns a function that will only execute the provided promise returning function
|
|
178
|
+
* with the most recently specified params only if a previously created promise does not exist.
|
|
179
|
+
*/
|
|
180
|
+
declare function bufferAsync<F extends (...args: any) => any, K>(func: (...params: Parameters<F>) => Promise<K>): (...params: Parameters<typeof func>) => Promise<K | undefined>;
|
|
181
|
+
/**
|
|
182
|
+
* Guarantees delay between invocations of the given function.
|
|
183
|
+
*
|
|
184
|
+
* Invocations of the throttled function after the given interval has passed will execute instantly.
|
|
185
|
+
*
|
|
186
|
+
* Subsequent invocations during the cool down return a promise to invoke the function after the remaining delay has passed.
|
|
187
|
+
*
|
|
188
|
+
* Once the interval has passed, all queued promises are executed, but only the latest promise will execute the function. The others will return undefined.
|
|
189
|
+
* @param func the function to throttle
|
|
190
|
+
* @param delay milliseconds required between invocations of the function.
|
|
191
|
+
*/
|
|
192
|
+
declare function throttleQueueAsync<F extends (...args: any) => any, K>(func: (...params: Parameters<F>) => K | Promise<K>, delay: number): (...params: Parameters<typeof func>) => Promise<K | undefined>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Makes sure the object is not undefined and the trim length is greater than 0.
|
|
196
|
+
* @param value
|
|
197
|
+
* @returns Synchronous validator
|
|
198
|
+
*/
|
|
199
|
+
declare function required<T, P, V, R, A>(): SyncValidator<T, P, V, R, A>;
|
|
200
|
+
/**
|
|
201
|
+
* Makes sure the string or number to validate has a length >= to the provided length.
|
|
202
|
+
* @param minLength
|
|
203
|
+
* @returns Synchronous validator
|
|
204
|
+
*/
|
|
205
|
+
declare function minLength<T extends string | undefined | null, P, V, R, A>(minLength: number): SyncValidator<T, P, V, R, A>;
|
|
206
|
+
/**
|
|
207
|
+
* Makes sure the string or number to validate is less than the provided length. Undefined strings are treated as 0 length.
|
|
208
|
+
* @param maxLength
|
|
209
|
+
* @return Synchronous validator
|
|
210
|
+
*/
|
|
211
|
+
declare function maxLength<T extends string | number | undefined | null, P, V, R, A>(maxLength: number): SyncValidator<T, P, V, R, A>;
|
|
212
|
+
/**
|
|
213
|
+
* Makes sure the number to validate is not undefined and is at least the provided value.
|
|
214
|
+
* @param minNumber
|
|
215
|
+
* @returns Synchronous validator
|
|
216
|
+
*/
|
|
217
|
+
declare function minNumber<T extends number | undefined | null, P, V, R, A>(minNumber: number): SyncValidator<T, P, V, R, A>;
|
|
218
|
+
/**
|
|
219
|
+
* Makes sure the number to validate is not undefined and is at most the provided value.
|
|
220
|
+
* @param maxNumber
|
|
221
|
+
* @returns Synchronous validator
|
|
222
|
+
*/
|
|
223
|
+
declare function maxNumber<T extends number | undefined | null, P, V, R, A>(maxNumber: number): SyncValidator<T, P, V, R, A>;
|
|
224
|
+
/**
|
|
225
|
+
* Checks if the value of this property strictly equals the value returned by the provided getter.
|
|
226
|
+
*/
|
|
227
|
+
declare function mustEqual<T, P, V, R, A>(getter: (params: ValidatorParams<T, P, V, A>) => T, errorMessage: string): SyncValidator<T, P, V, R, A>;
|
|
228
|
+
/**
|
|
229
|
+
* Checks if the string value is a valid looking email using RegEx.
|
|
230
|
+
*
|
|
231
|
+
* The RegEx was taken from https://stackoverflow.com/questions/46155/how-can-i-validate-an-email-address-in-javascript, and may be updated in the future.
|
|
232
|
+
* @returns Synchronous validator
|
|
233
|
+
*/
|
|
234
|
+
declare function isEmailSync<T extends string | undefined | null, P, V, R, A>(): SyncValidator<T, P, V, R, A>;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* A simple and lightweight Vue3 model based validation library with strong type support.
|
|
238
|
+
*
|
|
239
|
+
* @author Daniel Walbolt
|
|
240
|
+
*/
|
|
241
|
+
declare function useValidation<T, Args = undefined, FValidationReturn = unknown>(validationConfig: ValidationConfig<T, Args | undefined, FValidationReturn>): {
|
|
242
|
+
hasValidated: boolean;
|
|
243
|
+
validate: () => Promise<boolean>;
|
|
244
|
+
isValidating: boolean;
|
|
245
|
+
propertyState: ValidationState<T, FValidationReturn>;
|
|
246
|
+
isValid: boolean;
|
|
247
|
+
setReference: (reference: T) => void;
|
|
248
|
+
isDirty: boolean;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export { ArrayValidationReturn, ArrayValidationState, ArrayValidatorTypes, AsyncValidator, BaseValidationReturn, BaseValidator, Primitive, PrimitiveValidation, PrimitiveValidationState, PrimitiveValidatorTypes, RecursiveValidation, RecursiveValidationState, SyncValidator, Validation, ValidationConfig, ValidationState, Validator, ValidatorParams, ValidatorTypes, bufferAsync, isEmailSync, maxLength, maxNumber, minLength, minNumber, mustEqual, required, throttleQueueAsync, useValidation };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var O=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var U=(a,e)=>{for(var t in e)O(a,t,{get:e[t],enumerable:!0})},Z=(a,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of q(e))!E.call(a,r)&&r!==t&&O(a,r,{get:()=>e[r],enumerable:!(i=Q(e,r))||i.enumerable});return a};var W=a=>Z(O({},"__esModule",{value:!0}),a);var b=(a,e,t)=>new Promise((i,r)=>{var o=n=>{try{V(t.next(n))}catch(l){r(l)}},d=n=>{try{V(t.throw(n))}catch(l){r(l)}},V=n=>n.done?i(n.value):Promise.resolve(n.value).then(o,d);V((t=t.apply(a,e)).next())});var ra={};U(ra,{bufferAsync:()=>h,isEmailSync:()=>ta,maxLength:()=>_,maxNumber:()=>ea,minLength:()=>Y,minNumber:()=>aa,required:()=>H,throttleQueueAsync:()=>G,useValidation:()=>C,validateIf:()=>X});module.exports=W(ra);function h(a){let e=0,t;return(...i)=>{var o;let r=++e;return t=(o=t==null?void 0:t.then(()=>{if(e===r)return t=a(...i).then(d=>(t=void 0,d)),t}))!=null?o:a(...i).then(d=>(t=void 0,d)),t}}function G(a,e){let t=0,i;return(...r)=>new Promise(o=>{let d=++t,V=new Date().getTime();i!=null||(i=V-e);let n=V-i-e;n<0?new Promise(l=>setTimeout(l,-1*n)).then(()=>{i=new Date().getTime(),d===t&&o(a(...r)),o(void 0)}):(i=V,o(a(...r)))})}function j(a,e=t=>t){return a.reduce((t,i)=>{if(i!==void 0){let r=e(i);r!==void 0&&t.push(r)}return t},[])}function M(a){return a.reduce((e,t)=>{if(t!==void 0)if(t instanceof Array)for(let i of t)i!==void 0&&e.push(i);else e.push(t);return e},[])}function H(){return a=>({isValid:a.value!==void 0&&String(a.value).trim().length>0,errorMessage:"This field is required"})}function X(a,e){return t=>b(this,null,function*(){return(yield a(t))===!1?{isValid:!0}:e})}function Y(a){return e=>{var i;let t=String((i=e.value)!=null?i:"");return{isValid:t.length>=a,errorMessage:`Too short (${t.length} / ${a})`}}}function _(a){return e=>{var i;let t=String((i=e.value)!=null?i:"");return{isValid:t.length<=a,errorMessage:`Too long (${t.length} / ${a})`}}}function aa(a){return e=>({isValid:e.value!==void 0&&e.value>=a,errorMessage:`The minimum value is ${a}`})}function ea(a){return e=>({isValid:e.value!==void 0&&e.value<=a,errorMessage:`The maximum value is ${a}`})}function ta(){return a=>({isValid:a.value?RegExp(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(a.value):!1,errorMessage:"Invalid email format"})}var R=require("vue");var N=require("vue");var v=require("vue");function k(){return`${Date.now()}-${Math.floor(Math.random()*1e3)}`}function S(a,e,t){let i=[],r=o=>`${e?"reactive":"lazy"}-${k()}`;t!=null&&(r=o=>`${t}-${o}`);for(let[o,d]of a.entries())i.push({validatorId:r(o),validator:d,optimized:!1,isReactive:e,previouslyReturnedValidators:!1,previouslySpawnedValidators:{},spawnedValidators:{}});return i}function x(a,e,t=[]){var l,y,u,s;let i=(0,v.reactive)({isValid:(0,v.computed)(()=>{var P,f;let c=(P=n.isLazyValid.value)!=null?P:!1,p=(f=n.isReactiveValid.value)!=null?f:!1;return c&&p}),isValidating:(0,v.computed)(()=>n.isValidatingReactive.value||n.isValidatingLazy.value),isErrored:(0,v.computed)(()=>i.resultsArray.some(c=>c.isValid===!1)),errorMessages:(0,v.computed)(()=>M(j(i.resultsArray,c=>c.isValid?void 0:c.errorMessage))),results:(0,v.computed)(()=>n.namedValidationResults.value),resultsArray:(0,v.computed)(()=>n.validationResults.value),arrayState:(0,v.computed)(()=>{if(Array.isArray(a.value)===!1||n.elementValidation===void 0)return[];console.time("Array state");let c=a.value,p=n.elementValidation,P=n.arrayConfigMap,f=[],A={},m,I=[];for(let g=0;g<c.length;g++){if(c[g]!==void 0&&typeof c[g]=="object"?(c[g].$ffId===void 0&&Object.defineProperty(c[g],"$ffId",{value:`${n.id}-${n.elementId++}`,writable:!1,configurable:!1,enumerable:!1}),m=c[g].$ffId):c[g]!==void 0&&(m=g),I.push(m),P[m]){f.push(P[m].validationState),A[m]=P[m];continue}if(w(p)){let T=(0,v.computed)(()=>c[g]),F=x(T,p,n.arrayParents);P[m]={validationConfigs:[F],validationState:F.validationState}}else{let T=c[g],F=$(T,p,n.arrayParents.concat(T));P[m]={validationConfigs:F.validationConfigs,validationState:F.state}}f.push(P[m].validationState),A[m]=P[m]}return n.arrayConfigMap=A,console.timeEnd("Array state"),f})}),r=!(((y=(l=e.$lazy)==null?void 0:l.length)!=null?y:-1)>0),o=!(((s=(u=e.$reactive)==null?void 0:u.length)!=null?s:-1)>0),d=e.$reactive?S(e.$reactive,!0):[],V=e.$lazy?S(e.$lazy,!1):[],n={id:k(),validationIterationId:0,isReactiveValid:(0,v.ref)(o),isValidatingReactive:(0,v.ref)(!1),reactiveProcessedValidators:d,isLazyValid:(0,v.ref)(r),isValidatingLazy:(0,v.ref)(!1),lazyProcessedValidators:V,property:a,validation:e,validationState:i,validationResults:(0,v.ref)([]),namedValidationResults:(0,v.ref)({}),arrayConfigMap:{},elementId:0,elementValidation:e.$each,arrayParents:(0,v.reactive)(t)};return n}function $(a,e,t=[]){let i=[],r={};e!==void 0&&o(a,e);function o(d,V){for(let n in V){let l=(0,v.computed)(()=>d[n]);if(w(V[n])){let y=V[n],u=x(l,y,t);i.push(u),r[n]=u.validationState}else{let y={},u=V[n];r[n]=y,o(l,u)}}}return{validationConfigs:i,state:r}}function w(a){return(a==null?void 0:a.$reactive)!==void 0||(a==null?void 0:a.$lazy)!==void 0||(a==null?void 0:a.$each)!==void 0}var z=500;function D(a,e,t,i,r){return b(this,null,function*(){let o=!0,d=(l,y,u)=>{if(i!==l.validationIterationId)return;u.isValid===!1&&(o=!1),u.id=y.validatorId;let s=l.validationResults.value.find(c=>c.id===u.id);s!==void 0?(Object.assign(s,u),u.name!==void 0&&l.namedValidationResults[u.name]!==void 0&&Object.assign(l.namedValidationResults.value[u.name],u)):(l.validationResults.value.push(u),u.name!==void 0&&(l.namedValidationResults.value[u.name]=u))},{asyncPromises:V,validatorsWhichPreviouslyReturnedValidators:n}=B(a,e,t,i,r,d,!0,1);if(yield Promise.all(V),i===a.validationIterationId){for(let l of n)for(let y of Object.keys(l.previouslySpawnedValidators))if(l.spawnedValidators[y]==null){let u=a.validationResults.value.findIndex(s=>s.id===y);u!==-1&&a.validationResults.value.splice(u)}}return o})}function B(a,e,t,i,r,o,d,V){let n=a.property.value,l=[],y=[],u=[];for(let s of r){let c=!1;s.previouslyReturnedValidators&&(s.previouslySpawnedValidators=s.spawnedValidators,s.spawnedValidators={},c=!0),s.previouslyReturnedValidators=!1;let p;if(s.computedValidator===void 0){let P={value:n,parent:e,args:t,arrayParents:a.arrayParents};p=s.validator(P)}else p=s.computedValidator.value;if(p instanceof Promise){let P=Date.now();l.push(p.then(f=>b(this,null,function*(){if(f===void 0){c&&u.push(s);return}let A=Date.now()-P;if(d&&A>z&&s.optimized===!1&&(s.optimized=!0,A<2*z?s.validator=G(s.validator,z):s.validator=h(s.validator)),Array.isArray(f)){let{asyncPromises:m,syncResults:I}=L(a,e,t,i,o,s,f,V);y.push(...I),yield Promise.all(m);return}else c&&u.push(s);o(a,s,f)})))}else if(Array.isArray(p)){let{asyncPromises:P,syncResults:f}=L(a,e,t,i,o,s,p,V);l.push(...P),y.push(...f)}else if(c&&u.push(s),p!==void 0){if(d&&s.optimized===!1){let P=s.validator;s.computedValidator=(0,N.computed)(()=>{let f={value:a.property.value,parent:e,args:t,arrayParents:a.arrayParents};return P(f)}),s.optimized=!0,s.validator=()=>s.computedValidator.value}y.push(p),o(a,s,p)}}return{asyncPromises:l,syncResults:y,validatorsWhichPreviouslyReturnedValidators:u}}function L(a,e,t,i,r,o,d,V){let n=S(d,o.isReactive,o.validatorId),l=B(a,e,t,i,n,r,!1,++V),y={};for(let u of n)y[u.validatorId]=u;return o.spawnedValidators=y,o.previouslyReturnedValidators=!0,l}function ia(a,e,t,i){return b(this,null,function*(){a.isValidatingReactive.value=!0;let r=yield D(a,e,t,i,a.reactiveProcessedValidators);return i===a.validationIterationId&&(a.isReactiveValid.value=r,a.isValidatingReactive.value=!1),a.isReactiveValid.value})}function na(a,e,t,i){return b(this,null,function*(){a.isValidatingLazy.value=!0;let r=a.lazyProcessedValidators,o=yield D(a,e,t,i,r);return i===a.validationIterationId&&(a.isLazyValid.value=o,a.isValidatingLazy.value=!1),a.isLazyValid.value})}function K(a,e,t,i,r){return b(this,null,function*(){let o=[];for(let d of a){let V=++d.validationIterationId;if(i&&d.validation.$reactive!==void 0&&o.push(yield ia(d,e.value,t,V)),r&&d.validation.$lazy!==void 0&&o.push(yield na(d,e.value,t,V)),d.elementValidation!==void 0){let n=[];for(let l in d.arrayConfigMap)n.push(...d.arrayConfigMap[l].validationConfigs);o.push(yield K(n,e,t,i,r))}}return Promise.all(o).then(d=>d.every(V=>V===!0))})}function C(a){var P;(P=a.delayReactiveValidation)!=null||(a.delayReactiveValidation=!0);let{objectToValidate:e,validation:t,delayReactiveValidation:i,args:r}=a,o=(0,R.ref)(!1),d=(0,R.computed)(()=>n.some(f=>f.validationState.isValidating)),V=(0,R.computed)(()=>n.every(A=>A.isReactiveValid.value&&A.isLazyValid.value)),n=[],l=(0,R.reactive)({}),y=(0,R.ref)(JSON.stringify(a.objectToValidate.value)),u=(0,R.computed)(()=>y.value!==JSON.stringify(a.objectToValidate.value));if(w(t)){let m=x(e,t);l=(0,R.reactive)(m.validationState),n=[m]}else{let f=e,A=t,m=$(f.value,A);l=(0,R.reactive)(m.state),n=m.validationConfigs}(0,R.watch)(a.objectToValidate,()=>{i?o.value===!0&&K(n,e,r,!0,!1):K(n,e,r,!0,!1)},{deep:!0});function c(){return b(this,null,function*(){let f=yield K(n,e,r,!0,!0);return o.value=!0,f})}function p(f){y.value=JSON.stringify(f)}return(0,R.reactive)({hasValidated:o,validate:c,isValidating:d,propertyState:(0,R.computed)(()=>l),isValid:V,setReference:p,isDirty:u})}0&&(module.exports={bufferAsync,isEmailSync,maxLength,maxNumber,minLength,minNumber,required,throttleQueueAsync,useValidation,validateIf});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var g=(a,e,t)=>new Promise((i,s)=>{var r=n=>{try{l(t.next(n))}catch(V){s(V)}},d=n=>{try{l(t.throw(n))}catch(V){s(V)}},l=n=>n.done?i(n.value):Promise.resolve(n.value).then(r,d);l((t=t.apply(a,e)).next())});function O(a){let e=0,t;return(...i)=>{var r;let s=++e;return t=(r=t==null?void 0:t.then(()=>{if(e===s)return t=a(...i).then(d=>(t=void 0,d)),t}))!=null?r:a(...i).then(d=>(t=void 0,d)),t}}function I(a,e){let t=0,i;return(...s)=>new Promise(r=>{let d=++t,l=new Date().getTime();i!=null||(i=l-e);let n=l-i-e;n<0?new Promise(V=>setTimeout(V,-1*n)).then(()=>{i=new Date().getTime(),d===t&&r(a(...s)),r(void 0)}):(i=l,r(a(...s)))})}function j(a,e=t=>t){return a.reduce((t,i)=>{if(i!==void 0){let s=e(i);s!==void 0&&t.push(s)}return t},[])}function aa(){return a=>({isValid:a.value!==void 0&&String(a.value).trim().length>0,errorMessage:"This field is required"})}function ea(a){return e=>{var i;let t=String((i=e.value)!=null?i:"");return{isValid:t.length>=a,errorMessage:`Too short (${t.length} / ${a})`}}}function ta(a){return e=>{var i;let t=String((i=e.value)!=null?i:"");return{isValid:t.length<=a,errorMessage:`Too long (${t.length} / ${a})`}}}function ia(a){return e=>({isValid:e.value!==void 0&&e.value>=a,errorMessage:`The minimum value is ${a}`})}function na(a){return e=>({isValid:e.value!==void 0&&e.value<=a,errorMessage:`The maximum value is ${a}`})}function ra(a,e){return t=>({isValid:t.value===a(t),errorMessage:e})}function oa(){return a=>({isValid:a.value?RegExp(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(a.value):!1,errorMessage:"Invalid email format"})}import{ref as B,computed as x,watch as W,reactive as q}from"vue";import{computed as Q}from"vue";import{computed as A,reactive as T,ref as b,toValue as J}from"vue";function M(){return`${Date.now()}-${Math.floor(Math.random()*1e3)}`}function k(a,e){let t,i;if(z(e)){let l=$(a,e);t=T(l.validationState),i=[l]}else{let l=L(a,e);t=T(l.state),i=l.validationConfigs}return{propertyState:t,validationConfigs:i}}function S(a,e,t){let i=[],s=()=>`${e?"reactive":"lazy"}-${M()}`;t!=null&&(s=r=>`${t}-${r}`);for(let[r,d]of a.entries())i.push({validatorId:s(r),validator:d,optimized:!1,isReactive:e,previouslyReturnedValidators:!1,previouslySpawnedValidators:{},spawnedValidators:{}});return i}function $(a,e,t=[]){var V,f,u,o;let i=T({isValid:A(()=>{var P,y;let c=(P=n.isLazyValid.value)!=null?P:!1,m=(y=n.isReactiveValid.value)!=null?y:!1;return c&&m}),isValidating:A(()=>n.isValidatingReactive.value||n.isValidatingLazy.value),isErrored:A(()=>i.resultsArray.some(c=>c.isValid===!1)),errorMessages:A(()=>j(i.resultsArray,c=>c.isValid?void 0:c.errorMessage)),results:A(()=>n.namedValidationResults.value),resultsArray:A(()=>n.validationResults.value),arrayState:A(()=>{if(Array.isArray(a.value)===!1||n.elementValidation===void 0)return[];console.time("Array state");let c=a.value,m=n.elementValidation,P=n.arrayConfigMap,y=[],p={},v,w=[];for(let R=0;R<c.length;R++){if(c[R]!==void 0&&typeof c[R]=="object"?(c[R].$ffId===void 0&&Object.defineProperty(c[R],"$ffId",{value:`${n.id}-${n.elementId++}`,writable:!1,configurable:!1,enumerable:!1}),v=c[R].$ffId):c[R]!==void 0&&(v=R),w.push(v),P[v]){y.push(P[v].validationState),p[v]=P[v];continue}if(z(m)){let G=A(()=>c[R]),K=$(G,m,n.arrayParents);P[v]={validationConfigs:[K],validationState:K.validationState}}else{let G=c[R],K=L(G,m,n.arrayParents.concat(G));P[v]={validationConfigs:K.validationConfigs,validationState:K.state}}y.push(P[v].validationState),p[v]=P[v]}return n.arrayConfigMap=p,console.timeEnd("Array state"),y})}),s=!(((f=(V=e.$lazy)==null?void 0:V.length)!=null?f:-1)>0),r=!(((o=(u=e.$reactive)==null?void 0:u.length)!=null?o:-1)>0),d=e.$reactive?S(e.$reactive,!0):[],l=e.$lazy?S(e.$lazy,!1):[],n={id:M(),validationIterationId:0,isReactiveValid:b(r),isValidatingReactive:b(!1),reactiveProcessedValidators:d,isLazyValid:b(s),isValidatingLazy:b(!1),lazyProcessedValidators:l,property:a,validation:e,validationState:i,validationResults:b([]),namedValidationResults:b({}),arrayConfigMap:{},elementId:0,elementValidation:e.$each,arrayParents:T(t)};return n}function L(a,e,t=[]){let i=[],s={};e!==void 0&&r(a,e);function r(d,l){for(let n in l){let V=A(()=>J(d)[n]);if(z(l[n])){let f=l[n],u=$(V,f,t);i.push(u),s[n]=u.validationState}else{let f={},u=l[n];s[n]=f,r(V,u)}}}return{validationConfigs:i,state:s}}function z(a){return(a==null?void 0:a.$reactive)!==void 0||(a==null?void 0:a.$lazy)!==void 0||(a==null?void 0:a.$each)!==void 0}var h=250;function D(a,e,t,i,s){return g(this,null,function*(){let r=!0,d=(V,f,u)=>{if(i!==V.validationIterationId)return;u.isValid===!1&&(r=!1),u.id=f.validatorId;let o=V.validationResults.value.find(c=>c.id===u.id);o!==void 0?(Object.assign(o,u),u.name!==void 0&&V.namedValidationResults[u.name]!==void 0&&Object.assign(V.namedValidationResults.value[u.name],u)):(V.validationResults.value.push(u),u.name!==void 0&&(V.namedValidationResults.value[u.name]=u))},{asyncPromises:l,validatorsWhichPreviouslyReturnedValidators:n}=N(a,e,t,i,s,d,!0,1);if(yield Promise.all(l),i===a.validationIterationId){for(let V of n)for(let f of Object.keys(V.previouslySpawnedValidators))if(V.spawnedValidators[f]==null){let u=a.validationResults.value.findIndex(o=>o.id===f);u!==-1&&a.validationResults.value.splice(u)}}return r})}function N(a,e,t,i,s,r,d,l){let n=a.property.value,V=[],f=[],u=[];for(let o of s){let c=!1;o.previouslyReturnedValidators&&(o.previouslySpawnedValidators=o.spawnedValidators,o.spawnedValidators={},c=!0),o.previouslyReturnedValidators=!1;let m;if(o.computedValidator===void 0){let P={value:n,parent:e,args:t,arrayParents:a.arrayParents};m=o.validator(P)}else m=o.computedValidator.value;if(m instanceof Promise){let P=Date.now();V.push(m.then(y=>g(this,null,function*(){if(y===void 0){c&&u.push(o);return}let p=Date.now()-P;if(d&&p>h&&o.optimized===!1&&(o.optimized=!0,p>h&&p<2*h?o.validator=I(o.validator,h):o.validator=O(o.validator)),Array.isArray(y)){let{asyncPromises:v,syncResults:w}=C(a,e,t,i,r,o,y,l);f.push(...w),yield Promise.all(v);return}else c&&u.push(o);r(a,o,y)})))}else if(Array.isArray(m)){let{asyncPromises:P,syncResults:y}=C(a,e,t,i,r,o,m,l);V.push(...P),f.push(...y)}else if(c&&u.push(o),m!==void 0){if(d&&o.optimized===!1){let P=o.validator;o.computedValidator=Q(()=>{let y={value:a.property.value,parent:e,args:t,arrayParents:a.arrayParents};return P(y)}),o.optimized=!0,o.validator=()=>o.computedValidator.value}f.push(m),r(a,o,m)}}return{asyncPromises:V,syncResults:f,validatorsWhichPreviouslyReturnedValidators:u}}function C(a,e,t,i,s,r,d,l){let n=S(d,r.isReactive,r.validatorId),V=N(a,e,t,i,n,s,!1,++l),f={};for(let u of n)f[u.validatorId]=u;return r.spawnedValidators=f,r.previouslyReturnedValidators=!0,V}function U(a,e,t,i){return g(this,null,function*(){a.isValidatingReactive.value=!0;let s=yield D(a,e,t,i,a.reactiveProcessedValidators);return i===a.validationIterationId&&(a.isReactiveValid.value=s,a.isValidatingReactive.value=!1),a.isReactiveValid.value})}function Z(a,e,t,i){return g(this,null,function*(){a.isValidatingLazy.value=!0;let s=a.lazyProcessedValidators,r=yield D(a,e,t,i,s);return i===a.validationIterationId&&(a.isLazyValid.value=r,a.isValidatingLazy.value=!1),a.isLazyValid.value})}function F(a,e,t,i,s){return g(this,null,function*(){let r=[];for(let d of a){let l=++d.validationIterationId;if(i&&d.validation.$reactive!==void 0&&r.push(yield U(d,e.value,t,l)),s&&d.validation.$lazy!==void 0&&r.push(yield Z(d,e.value,t,l)),d.elementValidation!==void 0){let n=[];for(let V in d.arrayConfigMap)n.push(...d.arrayConfigMap[V].validationConfigs);r.push(yield F(n,e,t,i,s))}}return Promise.all(r).then(d=>d.every(l=>l===!0))})}function H(a){var P;(P=a.delayReactiveValidation)!=null||(a.delayReactiveValidation=!0);let{objectToValidate:e,validation:t,delayReactiveValidation:i,args:s}=a,r=B(!1),d=x(()=>n.some(y=>y.validationState.isValidating)),l=x(()=>n.every(p=>p.isReactiveValid.value&&p.isLazyValid.value)),n=[],V=q({}),f=B(JSON.stringify(a.objectToValidate.value)),u=x(()=>f.value!==JSON.stringify(a.objectToValidate.value)),o=k(e,t);V=o.propertyState,n=o.validationConfigs,W(a.objectToValidate,()=>{i?r.value===!0&&F(n,e,s,!0,!1):F(n,e,s,!0,!1)},{deep:!0});function c(){return g(this,null,function*(){let y=yield F(n,e,s,!0,!0);return r.value=!0,y})}function m(y){f.value=JSON.stringify(y)}return q({hasValidated:r,validate:c,isValidating:d,propertyState:x(()=>V),isValid:l,setReference:m,isDirty:u})}export{O as bufferAsync,oa as isEmailSync,ta as maxLength,na as maxNumber,ea as minLength,ia as minNumber,ra as mustEqual,aa as required,I as throttleQueueAsync,H as useValidation};
|
package/favicon.ico
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vuelidify",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "Daniel Walbolt",
|
|
5
|
+
"private": false,
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"icon": "./favicon.ico",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"favicon.ico",
|
|
13
|
+
"assets"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/Daniel-Walbolt/vue-final-form",
|
|
16
|
+
"issues": "https://github.com/Daniel-Walbolt/vue-final-form/issues",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Daniel-Walbolt/vue-final-form"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"vue": "^3.4.38"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@tsconfig/node20": "^20.1.4",
|
|
26
|
+
"@types/node": "^20.16.2",
|
|
27
|
+
"@vitejs/plugin-vue": "^5.1.3",
|
|
28
|
+
"@vue/eslint-config-typescript": "^13.0.0",
|
|
29
|
+
"@vue/tsconfig": "^0.5.1",
|
|
30
|
+
"eslint": "^8.57.0",
|
|
31
|
+
"eslint-plugin-vue": "^9.27.0",
|
|
32
|
+
"npm-run-all2": "^6.2.2",
|
|
33
|
+
"tsup": "^6.7.0",
|
|
34
|
+
"typescript": "~5.4.5",
|
|
35
|
+
"vue-tsc": "^2.1.2"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup src/index.ts --format esm --dts --minify",
|
|
39
|
+
"lint": "tsc"
|
|
40
|
+
}
|
|
41
|
+
}
|