vuelidify 2.0.1 → 2.0.3

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 (2) hide show
  1. package/README.md +58 -19
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,12 +1,19 @@
1
1
  # Vuelidify
2
+ Powerful and typed model-based validation for Vue 3
2
3
 
3
4
  [Installation](#installation)
5
+
4
6
  [Types](#types)
7
+
5
8
  [Examples](#examples)
6
- [Technical Details](#technical-details)
9
+
10
+ [Provided Validators](#provided-validators)
11
+
7
12
  [Custom Validators](#custom-validators)
13
+
14
+ [Technical Details](#technical-details)
15
+
8
16
  ---
9
- *Vuelidify is a Vue 3 model-based validation library that makes complex form validation easy.*
10
17
 
11
18
  This library was inspired by Vuelidate and sought to solve some of its biggest problems. This library does NOT support Vue2, and does NOT support commonJS. Technology must move forward.
12
19
 
@@ -362,23 +369,37 @@ const bErrors = v$.state.b?.$arrayState;
362
369
  ```
363
370
  Note, properties may show up in the intellisense, but they are undefinable *on purpose*. If validation rules are not provided for a property, its state object will not exist.
364
371
 
365
- ## Technical Details
366
- For those interested in the inner workings of the library without looking at the code:
367
-
368
- - Reactive validation is performed by a deep watcher on the provided model. 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 *every* time the model is changed. However, the problem is mediated by validator optimizations which is discussed later.
369
- - 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 model itself may be valid before ever calling `validate()` if there were no lazy validators provided, and all reactive validators were true (or again none specified).
370
- - 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 in 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.
371
- - `throttleAsync` is an async throttler that preserves your function’s signature and always returns a Promise of its result. It executes immediately when idle; if called during the throttle interval, it buffers only the latest call and runs it once the interval elapses—earlier buffered calls resolve to `undefined`. This lets you schedule non-blocking, promise-based throttling without overlapping executions and guarantees you always call your function with the latest arguments. Note, you are unable to distinguish if your function returned `undefined` or `throttleAsync` returned `undefined`.
372
- - `bufferAsync` is another custom function exported by this library that provides a more aggressive throttling behavior than `throttleAsync`. `bufferAsync` preserves the original function’s signature and returns a promise resolving to its result. It only remembers the latest invocation while the provided function is still executing. Once the current execution completes, only the remembered call will be invoked — all intermediate calls will return `undefined`. This mechanism prevents overlapping executions and reduces redundant work, making it ideal for expensive async operations where only the most recent intent should be executed. Note, you are unable to distinguish if your function returned `undefined` or `bufferAsync` returned `undefined`.
373
- - Returning arrays of validators from within other validators is powerful but complex. Initially, we aimed to optimize these nested validators, but their dynamic nature--varying instances, order, and presence between iterations--made this unreliable. Since their results merge with all other validators, Vuelidify tracks and removes outdated results when the "parent" validator is invoked again and the same results are not returned.
374
- - This library uses `unknown` instead of `any` to align with Deno and strict TypeScript standards. While `Args` and `Ancestors` are logically `undefined` by default, using `undefined` as a type causes issues—`unknown` can't be assigned to `undefined`. This distinction is why some of Vuelidify’s types may seem unusual, especially when creating generic validators meant to work universally. Additionally, the default type of `Return` is `any` because it truly *can be* anything. If it was unknown, you would be unable to access it for anything. `Return` is the only part of Vuelidify that is not strongly-typed. Be sure to cast it to what you expect before using it.
372
+ # Provided Validators
373
+ Here are the validators that Vuelidify provides by default:
374
+
375
+ - ```ts
376
+ required()
377
+ ```
378
+ - ```ts
379
+ minLength(min: number)
380
+ ```
381
+ - ```ts
382
+ maxLength(max: number)
383
+ ```
384
+ - ```ts
385
+ minNumber(min: number)
386
+ ```
387
+ - ```ts
388
+ maxNumber(max: number)
389
+ ```
390
+ - ```ts
391
+ must(fn: (params) => boolean, errorMessage: string)
392
+ ```
393
+ - ```ts
394
+ isEmailSync()
395
+ ```
396
+
397
+ There aren't many validators provided by this library on purpose. If you feel a validator would be useful for everyone to have, give us feedback on our GitHub repository. However, we highly encourage you to understand how to make your own!
375
398
 
376
399
  # Custom Validators
377
- There aren't many validators provided by this library on purpose. Mostly because I would rather rely on feedback for useful validators. Feel free to give me feedback on the github repo.
378
-
379
- 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 your validator off of existing ones.
400
+ This section guides you to create your own generic validators. Validators were designed to be easy to create and easier to use.
380
401
 
381
- Here is a breakdown of one of the validators exported by this library (expanded to make comments more readable):
402
+ Here is a breakdown of one of the built-in validators (expanded to make comments more readable):
382
403
 
383
404
  ```ts
384
405
  // always provide a header comment to explain what the validator does!
@@ -398,12 +419,11 @@ export function isEmailSync<
398
419
  V,
399
420
  // The type for the custom return from the validator
400
421
  R,
401
- // The type for the arrayParents parameter.
422
+ // The type for the arrayAncestors parameter.
402
423
  // Generally you don't put constraints on this.
403
- // But you have to accept this generic in order to pass the type forward to not mess up outside types.
404
424
  A
405
425
  >(
406
- // Specify any parameters you need here. This is a function that returns a validator.
426
+ // Specify any parameters you need here. This can be configuration (like a max length) or reactive variables.
407
427
  ): SyncValidator<T, P, V, R, A> // Explicitly type the validator you'll be returning
408
428
  {
409
429
  // Return a validator function
@@ -438,4 +458,23 @@ export function isEmailSync<T extends string | undefined | null>(): SyncValidato
438
458
 
439
459
  This validator is effectively: `SyncValidator<string | undefined | null, unknown, unknown, unknown, unknown>`
440
460
 
461
+ ## Technical Details
462
+ For those interested in the inner workings of the library without looking at the code:
463
+
464
+ - Reactive validation is performed by a deep watcher on the provided model. 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 *every* time the model is changed. However, the problem is mediated by validator optimizations which is discussed later.
465
+
466
+ - 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 model itself may be valid before ever calling `validate()` if there were no lazy validators provided, and all reactive validators were true (or again none specified).
467
+
468
+ - Validation results are ideally visible as soon as possible. Synchronous validation should not wait for async validation to finish before displaying errors. Vuelidify implements this by running all validators concurrently, and assimilating the validation results as they finish. This is fairly intuitive. However, what happens when you have lazy validation and reactive validation? You can't replace the array every time a new validation cycle happens, because that could lose the results from lazy validation! Each validator is assigned an ID internally. This ID is used for identifying the results from validators. When a result is returned, Vuelidify determines if it already exists in the results array. If it does, then Vuelidify updates all the data in that result to the data from the new result. This feature is particularly useful if you want to do animations on validation errors, because the error won't be leaving and re-entering the array every time validation is done.
469
+
470
+ - 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 in 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.
471
+
472
+ - `throttleAsync` is an async throttler that preserves your function’s signature and always returns a Promise of its result. It executes immediately when idle; if called during the throttle interval, it buffers only the latest call and runs it once the interval elapses—earlier buffered calls resolve to `undefined`. This lets you schedule non-blocking, promise-based throttling without overlapping executions and guarantees you always call your function with the latest arguments. Note, you are unable to distinguish if your function returned `undefined` or `throttleAsync` returned `undefined`.
473
+
474
+ - `bufferAsync` is another custom function exported by this library that provides a more aggressive throttling behavior than `throttleAsync`. `bufferAsync` preserves the original function’s signature and returns a promise resolving to its result. It only remembers the latest invocation while the provided function is still executing. Once the current execution completes, only the remembered call will be invoked — all intermediate calls will return `undefined`. This mechanism prevents overlapping executions and reduces redundant work, making it ideal for expensive async operations where only the most recent intent should be executed. Note, you are unable to distinguish if your function returned `undefined` or `bufferAsync` returned `undefined`.
475
+
476
+ - Returning arrays of validators from within other validators is powerful but complex. Initially, we aimed to optimize these nested validators, but their dynamic nature--varying instances, order, and presence between iterations--made this unreliable. Since their results merge with all other validators, Vuelidify tracks and removes outdated results when the "parent" validator is invoked again and the same results are not returned.
477
+
478
+ - This library uses `unknown` instead of `any` to align with Deno and strict TypeScript standards. While `Args` and `Ancestors` are logically `undefined` by default, using `undefined` as a type causes issues—`unknown` can't be assigned to `undefined`. This distinction is why some of Vuelidify’s types may seem unusual, especially when creating generic validators meant to work universally. Additionally, the default type of `Return` is `any` because it truly *can be* anything; if it was unknown, you would be unable to access it. `Return` is the only part of Vuelidify that is not strongly-typed. Be sure to cast it to what you expect before using it.
479
+
441
480
  Feel free to post issues you may have with the package on the git repo! Happy validating!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vuelidify",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "author": "Daniel Walbolt",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",