vuelidify 2.1.1 → 2.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/README.md CHANGED
@@ -377,28 +377,37 @@ Note, your properties may show up in the intellisense for `state`, but they are
377
377
  Here are the validators that Vuelidify provides by default:
378
378
 
379
379
  - ```ts
380
- required()
380
+ required(message?: string)
381
+ ```
382
+ - ```ts
383
+ notEmpty(message?: string)
381
384
  ```
382
385
  - ```ts
383
- minLength(min: number)
386
+ minLength(min: number, message?: string)
384
387
  ```
385
388
  - ```ts
386
- maxLength(max: number)
389
+ maxLength(max: number, message?: string)
390
+ ```
391
+ - ```ts
392
+ minNumber(min: number, message?: string)
393
+ ```
394
+ - ```ts
395
+ exclusiveMinNumber(min: number, message?: string)
387
396
  ```
388
397
  - ```ts
389
- minNumber(min: number)
398
+ maxNumber(max: number, message?: string)
390
399
  ```
391
400
  - ```ts
392
- maxNumber(max: number)
401
+ exclusiveMaxNumber(max: number, message?: string)
393
402
  ```
394
403
  - ```ts
395
- must(fn: (params) => boolean, errorMessage: string)
404
+ must(fn: (params) => boolean, message: string)
396
405
  ```
397
406
  - ```ts
398
407
  validateIf(predicate: (params) => boolean | Promise<boolean>, validators: Validator[])
399
408
  ```
400
409
  - ```ts
401
- isEmailSync()
410
+ isEmailSync(message?: string)
402
411
  ```
403
412
 
404
413
  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!
@@ -406,12 +415,13 @@ There aren't many validators provided by this library on purpose. If you feel a
406
415
  # Custom Validators
407
416
  This section guides you to create your own generic validators. Validators were designed to be easy to create and easier to use.
408
417
 
409
- Here is a breakdown of one of the built-in validators (expanded to make comments more readable):
418
+ Here is a breakdown of one of the provided validators (expanded to make comments more readable):
410
419
 
411
420
  ```ts
412
421
  // always provide a header comment to explain what the validator does!
413
422
  /**
414
423
  * Checks if the string value is a valid looking email using RegEx.
424
+ * @param message sets the error message returned.
415
425
  */
416
426
  export function isEmailSync<
417
427
  // The type of the property you want to support validation for.
@@ -430,7 +440,8 @@ export function isEmailSync<
430
440
  // Generally you don't put constraints on this.
431
441
  A
432
442
  >(
433
- // Specify any parameters you need here. This can be configuration (like a max length) or reactive variables.
443
+ // Specify any parameters here.
444
+ message?: string
434
445
  ): SyncValidator<T, K, V, R, A> // Explicitly type the validator you'll be returning
435
446
  {
436
447
  // Return a validator function
@@ -438,12 +449,14 @@ export function isEmailSync<
438
449
  // Strongly type the expected params object to have intellisense
439
450
  params: ValidatorParams<T, K, V, A>
440
451
  ) => {
441
- // you can do whatever you want a normal validator can in here.
442
- // Return undefined, an array of validators, or a validation result.
443
- // In this case, we're checking the value of the property against an email regex.
452
+ /**
453
+ * You can do whatever here, but you must return undefined,
454
+ * an array of validators, or a validation result.
455
+ * In this case, we're checking the value against an email regex.
456
+ */
444
457
  return {
445
458
  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,
446
- message: "Invalid email format"
459
+ message: message ?? "Invalid email format"
447
460
  }
448
461
  };
449
462
  }
@@ -454,11 +467,14 @@ Because every generic has a default value in `SyncValidator`, we can greatly sim
454
467
  ```ts
455
468
  /**
456
469
  * Validates a string is a valid looking email using RegEx.
470
+ * @param message sets the error message returned.
457
471
  */
458
- export function isEmailSync<T extends string | undefined | null>(): SyncValidator<T> {
472
+ export function isEmailSync<T extends string | undefined | null>(
473
+ message?: string
474
+ ): SyncValidator<T> {
459
475
  return (params: ValidatorParams<T>) => ({
460
476
  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,
461
- message: "Invalid email format"
477
+ message: message ?? "Invalid email format"
462
478
  });
463
479
  }
464
480
  ```
@@ -471,17 +487,17 @@ Vuelidify provides several throttling functions for limiting how often a functio
471
487
  - ```ts
472
488
  bufferAsync<F extends (...args: any[]) => any>(
473
489
  func: F,
474
- ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof IGNORE_RESULT>
490
+ ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>
475
491
  ```
476
- `bufferAsync` ensures that the provided function has only one instance executing at a time. Calls to the buffered function will return a promise to execute when the current instance returns. Only the latest promise will execute the function next, all other promises will resolve to `IGNORE_RESULT` once the current instance returns. This function is very useful for only invoking resource-heavy functions while guaranteeing each execution uses the most up-to-date parameters.
492
+ `bufferAsync` ensures that the provided function has only one instance executing at a time. Calls to the buffered function will return a promise to execute when the current instance returns. Only the latest promise will execute the function next, all other promises will resolve to `V$_IGNORE` once the current instance returns. This function is very useful for only invoking resource-heavy functions while guaranteeing each execution uses the most up-to-date parameters.
477
493
 
478
494
  - ```ts
479
495
  throttleBufferAsync<F extends (...args: any[]) => any>(
480
496
  func: F,
481
497
  delayMs: number,
482
- ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof IGNORE_RESULT>
498
+ ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>
483
499
  ```
484
- `throttleBufferAsync` behaves very similarly to `bufferAsync`, but instead of waiting for the current instance to return, it waits for a throttle duration to expire. Once the throttle expires the latest buffered promise will execute the function and all others will resolve to `IGNORE_RESULT`. This means multiple instances of the function could be running at the same time, depending on the throttle and how long the function takes to return.
500
+ `throttleBufferAsync` behaves very similarly to `bufferAsync`, but instead of waiting for the current instance to return, it waits for a throttle duration to expire. Once the throttle expires the latest buffered promise will execute the function and all others will resolve to `V$_IGNORE`. This means multiple instances of the function could be running at the same time, depending on the throttle and how long the function takes to return.
485
501
 
486
502
  - ```ts
487
503
  throttleAsync<F extends (...args: any) => any>(
@@ -489,20 +505,20 @@ Vuelidify provides several throttling functions for limiting how often a functio
489
505
  delayMs: number,
490
506
  ): {
491
507
  isThrottled: Ref<boolean>;
492
- throttledFunc: (...params: Parameters<F>) => ReturnType<F> | typeof IGNORE_RESULT;
508
+ throttledFunc: (...params: Parameters<F>) => ReturnType<F> | typeof V$_IGNORE;
493
509
  }
494
510
  ```
495
- `throttleAsync` ensures a function can only be invoked once every throttle period. Does not use buffering. Returns two objects, a ref indicating if the function is in its throttle period and the throttled function. Useful for hard limiting invocation of a function (e.g. forgot password form submission). Calls during the throttle period return `IGNORE_RESULT`.
511
+ `throttleAsync` ensures a function can only be invoked once every throttle period. Does not use buffering. Returns two objects, a ref indicating if the function is in its throttle period and the throttled function. Useful for hard limiting invocation of a function (e.g. forgot password form submission). Calls during the throttle period return `V$_IGNORE`.
496
512
 
497
513
  - ```ts
498
514
  trailingDebounceAsync<F extends (...args: any) => any>(
499
515
  func: F,
500
516
  delayMs: number,
501
- ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof IGNORE_RESULT>
517
+ ): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>
502
518
  ```
503
- `trailingDebounceAsync` ensures a function will only be invoked after a delay has passed since the last call. Guarantees the latest parameters will be executed. All calls prior to the latest will return `IGNORE_RESULT`.
519
+ `trailingDebounceAsync` ensures a function will only be invoked after a delay has passed since the last call. Guarantees the latest parameters will be executed. All calls prior to the latest will return `V$_IGNORE`.
504
520
 
505
- `IGNORE_RESULT` is a constant unique symbol exported by Vuelidify that helps you to identify when invocations are ignored by a throttle function. This was done to make sure this unique state doesn't conflict with possible returns from your own functions.
521
+ `V$_IGNORE` is a constant unique symbol exported by Vuelidify that helps you to identify when invocations are ignored by a throttle function. This was done to make sure this unique state doesn't conflict with possible returns from your own functions.
506
522
 
507
523
  ## Utility Functions
508
524
  Vuelidify provides a utility function you are free to use as well.
package/dist/index.d.ts CHANGED
@@ -76,6 +76,10 @@ type ArrayValidation<U, T = U[], KModel = unknown, Args = unknown, Return = any,
76
76
  [key in NLevel]: ArrayAncestor<U, T>;
77
77
  }, Increment<NLevel>>;
78
78
  };
79
+ /**
80
+ * Represents an element in {@link ValidatorParams.arrayAncestors | arrayAncestors} which
81
+ * holds context about the ancestor along with the ancestor itself.
82
+ */
79
83
  type ArrayAncestor<U = unknown, // the type of T's elements
80
84
  T = unknown> = Readonly<{
81
85
  /** The index this ancestor is at in `array` */
@@ -88,11 +92,11 @@ T = unknown> = Readonly<{
88
92
  /** A synchronous or asynchronous validator. */
89
93
  type Validator<T = unknown, KModel = unknown, Args = unknown, Return = any, Ancestors = unknown> = SyncValidator<T, KModel, Args, Return, Ancestors> | AsyncValidator<T, KModel, Args, Return, Ancestors>;
90
94
  /** Defines a validator function */
91
- type BaseValidator<T, Parent, Args, Return, Ancestors> = (input: ValidatorParams<T, Parent, Args, Ancestors>) => Return;
95
+ type BaseValidator<T, KModel, Args, Return, Ancestors> = (input: ValidatorParams<T, KModel, Args, Ancestors>) => Return;
92
96
  /** Defines a validator which always runs synchronously */
93
- type SyncValidator<T = unknown, Parent = unknown, Args = unknown, Return = any, Ancestors = unknown> = BaseValidator<T, Parent, Args, BaseValidationReturn<Return> | Array<Validator<T, Parent, Args, Return, Ancestors>> | undefined, Ancestors>;
97
+ type SyncValidator<T = unknown, KModel = unknown, Args = unknown, Return = any, Ancestors = unknown> = BaseValidator<T, KModel, Args, BaseValidationReturn<Return> | Array<Validator<T, KModel, Args, Return, Ancestors>> | undefined, Ancestors>;
94
98
  /** Defines a validator which returns a promise */
95
- type AsyncValidator<T = unknown, Parent = unknown, Args = unknown, Return = any, Ancestors = unknown> = BaseValidator<T, Parent, Args, Promise<BaseValidationReturn<Return> | Array<Validator<T, Parent, Args, Return, Ancestors>> | undefined>, Ancestors>;
99
+ type AsyncValidator<T = unknown, KModel = unknown, Args = unknown, Return = any, Ancestors = unknown> = BaseValidator<T, KModel, Args, Promise<BaseValidationReturn<Return> | Array<Validator<T, KModel, Args, Return, Ancestors>> | undefined>, Ancestors>;
96
100
  /** Defines the return value of validators */
97
101
  type BaseValidationReturn<F = unknown> = {
98
102
  /**
@@ -191,76 +195,170 @@ type Increment<N extends number> = [
191
195
  ...number[]
192
196
  ][N];
193
197
 
198
+ /** Vuelidify's constant Symbol used for identifying when a throttle function returned early. */
199
+ declare const V$_IGNORE: unique symbol;
194
200
  /**
195
- * Returns a function that will execute the provided function
196
- * with the latest params only if a previously created promise does not exist.
197
- * ```ts
198
- * async function test(): Promise<boolean> {}
199
- * // Call this constant instead of the function to get the buffer benefits
200
- * const bufferedTest = bufferAsync<
201
- * typeof test, // this type makes the return the same signature as test()
202
- * Awaited<ReturnType<typeof test>> // this type makes the returned function have the same return type
203
- * >(test);
204
- * ```
201
+ * Buffers a function such that only one instance of the function executes at a time.
202
+ *
203
+ * Calls during execution return a promise to execute the function after current execution finishes.
204
+ * Only the latest buffered call will execute the function; the rest resolve to {@link V$_IGNORE}.
205
+ *
206
+ * @param func The function to apply a buffer to.
207
+ *
208
+ * @example
209
+ * const buffered = bufferAsync(someAsyncFn);
210
+ * buffered('a'); // executes
211
+ * buffered('b'); // queued but will resolve to undefined
212
+ * buffered('c'); // queued and will executed after first completes
213
+ */
214
+ declare function bufferAsync<F extends (...args: any[]) => any>(func: F): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>;
215
+ /**
216
+ * Throttles and buffers a function such that it is only called once per delay period.
217
+ *
218
+ * Calls during the throttle return a promise to execute the function after the throttle.
219
+ * Only the latest buffered call will execute; the rest resolve to {@link V$_IGNORE}.
220
+ *
221
+ * Useful when you want to avoid spamming a resource and using the latest parameters is important.
222
+ *
223
+ * @param func - The function to throttle.
224
+ * @param delayMs - Time between invocations.
225
+ * @returns A throttled version of the function.
226
+ *
227
+ * @example
228
+ * async function saveInput(input: string) { ... }
229
+ * const throttledSave = throttleBufferAsync(saveInput, 1000);
230
+ *
231
+ * throttledSave("a"); // Executes immediately
232
+ * throttledSave("b"); // Queued but will resolve to IGNORE_RESULT
233
+ * throttledSave("c"); // Replaces "b", starts after 1s
234
+ *
235
+ * // Only "a" and "c" will be processed
236
+ */
237
+ declare function throttleBufferAsync<F extends (...args: any[]) => any>(func: F, delayMs: number): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>;
238
+ /**
239
+ * Adds trailing debounce behavior to a function.
240
+ *
241
+ * Waits for the specified delay after the last call before executing.
242
+ * All previous calls during the delay resolve to {@link V$_IGNORE}. Guarantees the call will have the latest parameters.
243
+ *
244
+ * @param func - The async function to debounce.
245
+ * @param delay - Delay in milliseconds after the last call before execution.
246
+ * @returns A debounced version of the function.
247
+ *
248
+ * @example
249
+ * async function fetchResults(query: string) { ... }
250
+ * const debouncedFetch = trailingDebounceAsync(fetchResults, 500);
251
+ *
252
+ * debouncedFetch("a"); // resolves to IGNORE_RESULT
253
+ * debouncedFetch("ab"); // resolves to IGNORE_RESULT
254
+ * debouncedFetch("abc"); // Only this call will be executed after 500ms
205
255
  */
206
- declare function bufferAsync<F extends (...args: any[]) => any, K>(func: (...params: Parameters<F>) => K | Promise<K>): (...params: Parameters<typeof func>) => Promise<K | undefined>;
256
+ declare function trailingDebounceAsync<F extends (...args: any) => any>(func: F, delayMs: number): (...params: Parameters<F>) => Promise<Awaited<ReturnType<F>> | typeof V$_IGNORE>;
207
257
  /**
208
- * Guarantees delay between invocations of the given function.
258
+ * Throttles a function, ensuring it's called once per delay period.
209
259
  *
210
- * Invocations of the throttled function after the given interval has passed will execute instantly.
260
+ * Calls during the delay are ignored, and the first call after the delay executes immediately.
211
261
  *
212
- * Subsequent invocations during the cool down return a promise to invoke the function after the remaining delay has passed.
262
+ * Useful for hard limiting actions (e.g. form submissions or API calls).
263
+ *
264
+ * @param func - The function to throttle.
265
+ * @param delayMs - The minimum time (in milliseconds) between calls.
266
+ * @returns A ref indicating throttle state and the throttled function.
267
+ *
268
+ * @example
269
+ * async function fetchResults(query: string) { ... }
270
+ * const { throttledFunc } = throttleAsync(fetchResults, 500);
271
+ *
272
+ * throttledFunc("a"); // executes immediately
273
+ * throttledFunc("ab"); // ignored
274
+ * // ... 500 ms later ...
275
+ * throttledFunc("abc"); // executes immediately
276
+ */
277
+ declare function throttleAsync<F extends (...args: any) => any>(func: F, delayMs: number): {
278
+ isThrottled: Ref<boolean>;
279
+ throttledFunc: (...params: Parameters<F>) => ReturnType<F> | typeof V$_IGNORE;
280
+ };
281
+
282
+ /**
283
+ * Accepts an array and uses the provided getter to get any value from each element
284
+ * and ignoring any undefined or null values returned.
213
285
  *
214
- * Once the interval has passed, all queued promises are executed, but only the latest promise will execute the function. The others will return undefined.
215
286
  * ```ts
216
- * async function test(): Promise<boolean> {}
217
- * // Call this constant instead of the function to get the throttle benefits
218
- * const throttledTest = throttleQueueAsync<
219
- * typeof test, // this type makes the return the same signature as test()
220
- * Awaited<ReturnType<typeof test>> // this type makes the returned function have the same return type
221
- * >(test);
287
+ * const array = [{ id: 123, name: "Foo"}, { id: 456, name: undefined }]
288
+ * const validNames = reduceUndefined(array, v => v.name) // ["Foo"]
222
289
  * ```
223
- * @param func the function to throttle
224
- * @param delay milliseconds required between invocations of the function.
290
+ * @param array the array to map values from
291
+ * @param getter a function executed with each element which can perform any kind of custom mapping.
292
+ * @returns an array of the getter's return value invoked with each source element, with undefined values omitted.
225
293
  */
226
- 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>;
294
+ declare function reduceUndefined<T, K = NonNullable<T>>(array: T[], getter?: (value: T) => K | undefined | null): K[];
227
295
 
228
296
  /**
229
297
  * Validates the object is not loosely undefined.
298
+ * This does allow for empty strings. If you need a non-empty value, use {@link notEmpty()}.
299
+ * @param message sets the error message returned.
230
300
  */
231
- declare function required(): SyncValidator;
301
+ declare function required(message?: string): SyncValidator;
302
+ /**
303
+ * Validates the object is not loosely undefined and is not an empty string.
304
+ * @param message sets the error message returned.
305
+ */
306
+ declare function notEmpty(message?: string): SyncValidator;
232
307
  /**
233
308
  * Validates a string or number has a length >= to the provided length. Undefined and null are 0 length.
234
- * @param minLength
309
+ * @param min the minimum length of the string or number.
310
+ * @param message sets the error message returned.
235
311
  */
236
- declare function minLength<T extends string | number | undefined | null>(minLength: number): SyncValidator<T>;
312
+ declare function minLength<T extends string | number | undefined | null>(min: number, message?: string): SyncValidator<T>;
237
313
  /**
238
314
  * Validates a string or number's length. Undefined and null are 0 length.
239
- * @param maxLength the maximum length of the string or number
315
+ * @param max the maximum length of the string or number.
316
+ * @param message sets the error message returned.
317
+ */
318
+ declare function maxLength<T extends string | number | undefined | null>(max: number, message?: string): SyncValidator<T>;
319
+ /**
320
+ * Validates a number is defined and is at least some value.
321
+ * @param min the minimum number the value can be.
322
+ * @param message sets the error message returned.
240
323
  */
241
- declare function maxLength<T extends string | number | undefined | null>(maxLength: number): SyncValidator<T>;
324
+ declare function minNumber<T extends number | undefined | null>(min: number, message?: string): SyncValidator<T>;
242
325
  /**
243
326
  * Validates a number is defined and is at least some value.
244
- * @param minNumber the minimum number the value can be
327
+ * @param min the minimum number the value can be.
328
+ * @param message sets the error message returned.
329
+ */
330
+ declare function exclusiveMinNumber<T extends number | undefined | null>(min: number, message?: string): SyncValidator<T>;
331
+ /**
332
+ * Validates a number is defined and is at most some value.
333
+ * @param max the maximum number the value can be.
334
+ * @param message sets the error message returned.
245
335
  */
246
- declare function minNumber<T extends number | undefined | null>(minNumber: number): SyncValidator<T>;
336
+ declare function maxNumber<T extends number | undefined | null>(max: number, message?: string): SyncValidator<T>;
247
337
  /**
248
338
  * Validates a number is defined and is at most some value.
249
- * @param maxNumber the maximum number the value can be
339
+ * @param max the maximum number the value can be.
340
+ * @param message sets the error message returned.
250
341
  */
251
- declare function maxNumber<T extends number | undefined | null>(maxNumber: number): SyncValidator<T>;
342
+ declare function exclusiveMaxNumber<T extends number | undefined | null>(max: number, message?: string): SyncValidator<T>;
252
343
  /**
253
344
  * Validate the provided predicate function.
254
345
  * @param fn predicate that returns true if the value is valid.
255
- * @param errorMessage the message to display when the values are not equal.
346
+ * @param message sets the error message returned.
256
347
  */
257
- declare function must<T, K, V, R, A>(fn: (params: ValidatorParams<T, K, V, A>) => boolean, errorMessage: string): SyncValidator<T, K, V, R, A>;
348
+ declare function must<T, K, V, R, A>(fn: (params: ValidatorParams<T, K, V, A>) => boolean, message: string): SyncValidator<T, K, V, R, A>;
349
+ /**
350
+ * Execute a set of validators only if the provided predicate is true.
351
+ * @param predicate determines if the set of validators should be returned.
352
+ * @param validators The set of validators to execute if the predicate returns true.
353
+ */
354
+ declare function validateIf<T, K, V, R, A, Validators extends Validator<T, K, V, R, A>[]>(predicate: (params: ValidatorParams<T, K, V, A>) => boolean | Promise<boolean>, validators: Validators): AsyncValidator<T, K, V, R, A>;
258
355
  /**
259
356
  * Validates a string is a valid looking email using RegEx.
260
357
  *
261
358
  * 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.
262
- s */
263
- declare function isEmailSync<T extends string | undefined | null>(): SyncValidator<T>;
359
+ * @param message sets the error message returned.
360
+ */
361
+ declare function isEmailSync<T extends string | undefined | null>(message?: string): SyncValidator<T>;
264
362
 
265
363
  type UseValidationReturn<T = unknown, Return = any> = {
266
364
  hasValidated: Ref<boolean>;
@@ -280,6 +378,10 @@ type UseValidationReturn<T = unknown, Return = any> = {
280
378
  * The reference state can be changed using {@link setReference()}.
281
379
  */
282
380
  isDirty: ComputedRef<boolean>;
381
+ /**
382
+ * Resets the internal state of the composable back to its starting state.
383
+ */
384
+ reset: () => void;
283
385
  };
284
386
  /**
285
387
  * The starting point for validation with Vuelidify.
@@ -288,4 +390,4 @@ type UseValidationReturn<T = unknown, Return = any> = {
288
390
  */
289
391
  declare function useValidation<T, Args = unknown, Return = any>(validationConfig: ValidationConfig<T, Args, Return>): Reactive<UseValidationReturn<T, Return>>;
290
392
 
291
- export { ArrayAncestor, ArrayValidation, ArrayValidationState, AsyncValidator, BaseValidation, BaseValidationReturn, BaseValidationState, BaseValidator, ObjectValidationTypes, Primitive, PrimitiveValidationState, RecursiveValidation, RecursiveValidationState, SyncValidator, Validation, ValidationConfig, ValidationState, Validator, ValidatorParams, bufferAsync, isEmailSync, maxLength, maxNumber, minLength, minNumber, must, required, throttleQueueAsync, useValidation };
393
+ export { ArrayAncestor, ArrayValidation, ArrayValidationState, AsyncValidator, BaseValidation, BaseValidationReturn, BaseValidationState, BaseValidator, ObjectValidationTypes, Primitive, PrimitiveValidationState, RecursiveValidation, RecursiveValidationState, SyncValidator, V$_IGNORE, Validation, ValidationConfig, ValidationState, Validator, ValidatorParams, bufferAsync, exclusiveMaxNumber, exclusiveMinNumber, isEmailSync, maxLength, maxNumber, minLength, minNumber, must, notEmpty, reduceUndefined, required, throttleAsync, throttleBufferAsync, trailingDebounceAsync, useValidation, validateIf };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- function x(e){let t=0,i;return(...r)=>{let o=++t;return i=(i==null?void 0:i.then(()=>{if(t===o)return i=new Promise(n=>n(e(...r))).then(n=>(i=void 0,n)),i}))??new Promise(n=>n(e(...r))).then(n=>(i=void 0,n)),i}}function S(e,t){let i=0,r;return(...o)=>new Promise(n=>{let l=++i,f=new Date().getTime();r??(r=f-t);let d=f-r-t;d<0?new Promise(u=>setTimeout(u,-1*d)).then(()=>{r=new Date().getTime(),l===i&&n(e(...o)),n(void 0)}):(r=f,n(e(...o)))})}function I(e,t=i=>i){return e.reduce((i,r)=>{if(r!==void 0){let o=t(r);o!==void 0&&i.push(o)}return i},[])}function X(){return e=>({isValid:e.value!=null,message:"This field is required"})}function Y(e){return t=>{let i=String(t.value??"");return{isValid:i.length>=e,message:`Too short (${i.length} / ${e})`}}}function _(e){return t=>{let i=String(t.value??"");return{isValid:i.length<=e,message:`Too long (${i.length} / ${e})`}}}function ee(e){return t=>({isValid:t.value!=null&&t.value>=e,message:`The minimum value is ${e}`})}function ae(e){return t=>({isValid:t.value!=null&&t.value<=e,message:`The maximum value is ${e}`})}function te(e,t){return i=>({isValid:e(i),message:t})}function ie(){return e=>({isValid:e.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(e.value):!1,message:"Invalid email format"})}import{computed as b,reactive as q,ref as N,watch as Z}from"vue";import{computed as U,toValue as G}from"vue";import{computed as R,reactive as O,ref as P,toValue as M}from"vue";function L(){return`${Date.now()}-${Math.floor(Math.random()*1e3)}`}function C(e,t){return D(e,t)}function A(e,t,i){let r=[],o=()=>`${t?"reactive":"lazy"}-${L()}`;i!=null&&(o=n=>`${i}-${n}`);for(let[n,l]of e.entries())r.push({validatorId:o(n),validator:l,optimized:!1,isReactive:t,previouslyReturnedValidators:!1,previouslySpawnedValidators:{},spawnedValidators:{}});return r}function K(e,t,i=[]){var u;let r=O({$state:{isValid:R(()=>{let s=d.isLazyValid.value??!1,c=d.isReactiveValid.value??!1;return s&&c}),isValidating:R(()=>d.isValidatingReactive.value||d.isValidatingLazy.value),isErrored:R(()=>{var s;return((s=r.$state)==null?void 0:s.resultsArray.some(c=>c.isValid===!1))??!1}),errorMessages:R(()=>{var s;return I(((s=r.$state)==null?void 0:s.resultsArray)??[],c=>c.isValid?void 0:c.message)}),results:R(()=>d.namedValidationResults.value),resultsArray:R(()=>d.validationResults.value)},$arrayState:R(()=>{if(Array.isArray(e.value)===!1||d.elementValidation===void 0)return[];let s=e.value,c=d.elementValidation,a=d.arrayConfigMap,v=[],m={},y,V=[];for(let p=0;p<s.length;p++){let T=s[p]!==void 0&&typeof s[p]=="object";if(T?(s[p].$ffId===void 0&&Object.defineProperty(s[p],"$ffId",{value:`${d.id}-${d.elementId++}`,writable:!1,configurable:!1,enumerable:!1}),y=s[p].$ffId):s[p]!==void 0&&(y=p),V.push(y),a[y]){v.push(a[y].validationState),m[y]=a[y];continue}let h=R(()=>s[p]),z=[...d.arrayAncestors];T&&z.push({ancestor:h,array:s,index:p});let k=D(h,c,z);a[y]={validationConfigs:k.validationConfigs,validationState:k.state},v.push(a[y].validationState),m[y]=a[y]}return d.arrayConfigMap=m,v})}),o=!0,n=!0,l=[],f=[];t.$reactive&&t.$reactive.length>0&&(n=!1,l=A(t.$reactive,!0)),t.$lazy&&((u=t.$lazy)==null?void 0:u.length)>0&&(o=!1,f=A(t.$lazy,!1));let d={id:L(),reactiveIterationId:0,lazyIterationId:0,isReactiveValid:P(n),isValidatingReactive:P(!1),reactiveProcessedValidators:l,isLazyValid:P(o),isValidatingLazy:P(!1),lazyProcessedValidators:f,target:e,validation:t,validationState:r,validationResults:P([]),namedValidationResults:P({}),arrayConfigMap:{},elementId:0,elementValidation:t.$each,arrayAncestors:O(i)};return d}function D(e,t,i=[]){let r=[],o={};if(j(t)){let l=R(()=>M(e)),f=K(l,t,i);r.push(f),o=f.validationState}t!=null&&n(e,t,o);function n(l,f,d){if($(f)!==!1)for(let u in f){if(u==="$reactive"||u==="$lazy"||u==="$each")continue;let s=R(()=>{let a=M(l);return $(a)?a[u]:(console.error(`Vuelidify Error: validation could not be setup correctly on ${a} because ${l} is not enumerable.`),null)}),c=f[u];if(j(c)){let a=K(s,c,i);r.push(a),d[u]=a.validationState}if($(c)){let a=d[u]??{};d[u]=a,n(s,c,a)}}}return{validationConfigs:r,state:o}}function j(e){return Array.isArray(e==null?void 0:e.$reactive)||Array.isArray(e==null?void 0:e.$lazy)||(e==null?void 0:e.$each)!==void 0}function $(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var w=250;async function B(e,t,i,r,o,n){let l=!0,f=(s,c,a)=>{if(r!==G(o))return;a.isValid===!1&&(l=!1),a.id=c.validatorId;let v=s.validationResults.value.find(m=>m.id===a.id);v!==void 0?(Object.assign(v,a),a.name!==void 0&&s.namedValidationResults.value[a.name]!==void 0&&Object.assign(s.namedValidationResults.value[a.name],a)):(s.validationResults.value.push(a),a.name!==void 0&&(s.namedValidationResults.value[a.name]=a))},{asyncPromises:d,validatorsWhichPreviouslyReturnedValidators:u}=F(e,t,i,r,n,f,!0,1);if(await Promise.all(d),r===G(o)){for(let s of u)for(let c of Object.keys(s.previouslySpawnedValidators))if(s.spawnedValidators[c]==null){let a=e.validationResults.value.findIndex(v=>v.id===c);a!==-1&&e.validationResults.value.splice(a)}}return l}function F(e,t,i,r,o,n,l,f){let d=e.target.value,u=[],s=[],c=[];for(let a of o){let v=!1;a.previouslyReturnedValidators&&(a.previouslySpawnedValidators=a.spawnedValidators,a.spawnedValidators={},v=!0),a.previouslyReturnedValidators=!1;let m;if(a.computedValidator===void 0){let y={value:d,model:t,args:i,arrayAncestors:e.arrayAncestors};m=a.validator(y)}else m=a.computedValidator.value;if(m instanceof Promise){let y=Date.now();u.push(m.then(async V=>{if(V===void 0){v&&c.push(a);return}let p=Date.now()-y;if(l&&p>w&&a.optimized===!1&&(a.optimized=!0,p>w&&p<2*w?a.validator=S(a.validator,w):a.validator=x(a.validator)),Array.isArray(V)){let{asyncPromises:T,syncResults:h}=E(e,t,i,r,n,a,V,f);s.push(...h),await Promise.all(T);return}else v&&c.push(a);n(e,a,V)}))}else if(Array.isArray(m)){let{asyncPromises:y,syncResults:V}=E(e,t,i,r,n,a,m,f);u.push(...y),s.push(...V)}else if(v&&c.push(a),m!==void 0){if(l&&a.optimized===!1){let y=a.validator;a.computedValidator=U(()=>{let V={value:e.target.value,model:t,args:i,arrayAncestors:e.arrayAncestors};return y(V)}),a.optimized=!0,a.validator=()=>{var V;return(V=a.computedValidator)==null?void 0:V.value}}s.push(m),n(e,a,m)}}return{asyncPromises:u,syncResults:s,validatorsWhichPreviouslyReturnedValidators:c}}function E(e,t,i,r,o,n,l,f){let d=A(l,n.isReactive,n.validatorId),u=F(e,t,i,r,d,o,!1,++f),s={};for(let c of d)s[c.validatorId]=c;return n.spawnedValidators=s,n.previouslyReturnedValidators=!0,u}async function J(e,t,i,r,o){e.isValidatingReactive.value=!0;let n=await B(e,t,i,r,o,e.reactiveProcessedValidators);return r===G(o)&&(e.isReactiveValid.value=n,e.isValidatingReactive.value=!1),e.isReactiveValid.value??!1}async function Q(e,t,i,r,o){e.isValidatingLazy.value=!0;let n=await B(e,t,i,r,o,e.lazyProcessedValidators);return r===G(o)&&(e.isLazyValid.value=n,e.isValidatingLazy.value=!1),e.isLazyValid.value??!1}function g(e,t,i,r,o){let n=[];for(let l of e)if(r&&l.reactiveProcessedValidators.length>0&&n.push(J(l,t.value,i,++l.reactiveIterationId,()=>l.reactiveIterationId)),o&&l.lazyProcessedValidators.length>0&&n.push(Q(l,t.value,i,++l.lazyIterationId,()=>l.lazyIterationId)),Array.isArray(l.validationState.$arrayState)){let f=[];for(let d in l.arrayConfigMap)f.push(...l.arrayConfigMap[d].validationConfigs);n.push(g(f,t,i,r,o))}return Promise.all(n).then(l=>l.every(f=>f===!0))}function W(e){e.delayReactiveValidation??(e.delayReactiveValidation=!0);let{model:t,validation:i,delayReactiveValidation:r,args:o}=e,n=N(!1),l=b(()=>u.some(V=>V.isValidatingLazy.value||V.isValidatingReactive.value)),f=b(()=>u.some(V=>V.validationResults.value.some(p=>p.isValid===!1))),d=b(()=>u.every(p=>p.isReactiveValid.value&&p.isLazyValid.value)),u=[],s=N(JSON.stringify(e.model.value)),c=b(()=>s.value!==JSON.stringify(e.model.value)),a=C(t,i),v=a.state;u=a.validationConfigs,Z(e.model,()=>{r?n.value===!0&&g(u,t,o,!0,!1):g(u,t,o,!0,!1)},{deep:!0});async function m(){let V=await g(u,t,o,!0,!0);return n.value=!0,V}function y(V){s.value=JSON.stringify(V)}return q({hasValidated:n,validate:m,isValidating:l,state:b(()=>v),isValid:d,isErrored:f,setReference:y,isDirty:c})}export{x as bufferAsync,ie as isEmailSync,_ as maxLength,ae as maxNumber,Y as minLength,ee as minNumber,te as must,X as required,S as throttleQueueAsync,W as useValidation};
1
+ import{ref as K}from"vue";var x=Symbol("Throttled function call was ignored");function H(e){let a=0,t;return(...n)=>{let r=++a;return(t??Promise.resolve()).then(()=>r!==a?x:e(...n)).finally(()=>{r===a&&(t=void 0)})}}function Q(e,a){let t=0,n=0;return async(...r)=>{let s=++t,f=Date.now()-n;return f<a&&(await new Promise(u=>setTimeout(u,a-f)),s!==t)?x:(n=Date.now(),await e(...r))}}function X(e,a){let t=0;return(...n)=>new Promise(r=>{let s=++t;setTimeout(async()=>{s==t?r(await e(...n)):r(x)},a)})}function Y(e,a){let t=K(!1);return{isThrottled:t,throttledFunc:(...r)=>t.value?x:(t.value=!0,setTimeout(()=>t.value=!1,a),e(...r))}}function O(e,a=t=>t){return e.reduce((t,n)=>{let r=a(n);return r!=null&&t.push(r),t},[])}function ae(e){return a=>({isValid:a.value!=null,message:e??"This field is required"})}function te(e){return a=>({isValid:a.value!=null&&a.value!==""&&String(a.value).trim().length>0,message:e??"Must not be empty"})}function ie(e,a){return t=>{let n=String(t.value??"");return{isValid:n.length>=e,message:a??`Too short (${n.length} / ${e})`}}}function ne(e,a){return t=>{let n=String(t.value??"");return{isValid:n.length<=e,message:a??`Too long (${n.length} / ${e})`}}}function re(e,a){return t=>({isValid:t.value!=null&&t.value>=e&&String(t.value)!=="",message:a??`The minimum value is ${e}`})}function oe(e,a){return t=>({isValid:t.value!=null&&t.value>e&&String(t.value)!=="",message:a??`The minimum value is ${e}`})}function se(e,a){return t=>({isValid:t.value!=null&&t.value<=e&&String(t.value)!=="",message:a??`The maximum value is ${e}`})}function le(e,a){return t=>({isValid:t.value!=null&&t.value<e&&String(t.value)!=="",message:a??`The maximum value is ${e}`})}function de(e,a){return t=>({isValid:e(t),message:a})}function ue(e,a){return async t=>{if(await e(t))return a}}function ce(e){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,message:e??"Invalid email format"})}import{computed as h,reactive as U,ref as E,watch as q}from"vue";import{computed as D,toValue as G}from"vue";import{computed as b,reactive as k,ref as T,toValue as F}from"vue";function L(){return`${Date.now()}-${Math.floor(Math.random()*1e3)}`}function z(e,a){return C(e,a)}function w(e,a,t){let n=[],r=()=>`${a?"reactive":"lazy"}-${L()}`;t!=null&&(r=s=>`${t}-${s}`);for(let[s,d]of e.entries())n.push({validatorId:r(s),validator:d,optimized:!1,isReactive:a,previouslyReturnedValidators:!1,previouslySpawnedValidators:{},spawnedValidators:{}});return n}function M(e,a,t=[]){let n=k({$state:{isValid:b(()=>{let l=u.isLazyValid.value??!1,g=u.isReactiveValid.value??!1;return l&&g}),isValidating:b(()=>u.isValidatingReactive.value||u.isValidatingLazy.value),isErrored:b(()=>n.$state?.resultsArray.some(l=>l.isValid===!1)??!1),errorMessages:b(()=>O(n.$state?.resultsArray??[],l=>l.isValid?void 0:l.message)),results:b(()=>u.namedValidationResults.value),resultsArray:b(()=>u.validationResults.value)},$arrayState:b(()=>{if(Array.isArray(e.value)===!1||u.elementValidation===void 0)return[];let l=e.value,g=u.elementValidation,m=u.arrayConfigMap,i=[],V={},o,p=[];for(let c=0;c<l.length;c++){let v=l[c]!==void 0&&typeof l[c]=="object";if(v?(l[c].$ffId===void 0&&Object.defineProperty(l[c],"$ffId",{value:`${u.id}-${u.elementId++}`,writable:!1,configurable:!1,enumerable:!1}),o=l[c].$ffId):l[c]!==void 0&&(o=c),p.push(o),m[o]){i.push(m[o].validationState),V[o]=m[o];continue}let y=b(()=>l[c]),R=[...u.arrayAncestors];v&&R.push({ancestor:y,array:l,index:c});let P=C(y,g,R);m[o]={validationConfigs:P.validationConfigs,validationState:P.state},i.push(m[o].validationState),V[o]=m[o]}return u.arrayConfigMap=V,i})}),r=!0,s=!0,d=[],f=[];a.$reactive&&a.$reactive.length>0&&(s=!1,d=w(a.$reactive,!0)),a.$lazy&&a.$lazy?.length>0&&(r=!1,f=w(a.$lazy,!1));let u={id:L(),reactiveIterationId:0,lazyIterationId:0,isReactiveValid:T(s),isValidatingReactive:T(!1),reactiveProcessedValidators:d,isLazyValid:T(r),isValidatingLazy:T(!1),lazyProcessedValidators:f,target:e,validation:a,validationState:n,validationResults:T([]),namedValidationResults:T({}),arrayConfigMap:{},elementId:0,elementValidation:a.$each,arrayAncestors:k(t)};return u}function C(e,a,t=[]){let n=[],r={};if(N(a)){let d=b(()=>F(e)),f=M(d,a,t);n.push(f),r=f.validationState}a!=null&&s(e,a,r);function s(d,f,u){if(I(f)!==!1)for(let l in f){if(l==="$reactive"||l==="$lazy"||l==="$each")continue;let g=b(()=>{let i=F(d);return I(i)?i[l]:(console.error(`Vuelidify Error: validation could not be setup correctly on ${i} because ${d} is not enumerable.`),null)}),m=f[l];if(N(m)){let i=M(g,m,t);n.push(i),u[l]=i.validationState}if(I(m)){let i=u[l]??{};u[l]=i,s(g,m,i)}}}return{validationConfigs:n,state:r}}function N(e){return Array.isArray(e?.$reactive)||Array.isArray(e?.$lazy)||e?.$each!==void 0}function I(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}async function j(e,a,t,n,r,s){let d=!0,f=(i,V,o)=>{if(n!==G(r))return;o.isValid===!1&&(d=!1),o.id=V.validatorId;let p=i.validationResults.value.find(c=>c.id===o.id);p!==void 0?(Object.assign(p,o),o.name!==void 0&&i.namedValidationResults.value[o.name]!==void 0&&Object.assign(i.namedValidationResults.value[o.name],o)):(i.validationResults.value.push(o),o.name!==void 0&&(i.namedValidationResults.value[o.name]=o))},u=[];for(let i of s){let V=(i.activeValidation??Promise.resolve()).then(async()=>n!==G(r)?[]:await g(i,!0));i.activeValidation=V,u.push(V)}return await Promise.all(u),d;function l(i,V){let o=[];for(let p of i)o.push(g(p,!1,V));return o}async function g(i,V,o=i){let p=[],c=i.previouslyReturnedValidators;c&&(i.previouslySpawnedValidators=i.spawnedValidators,i.spawnedValidators={}),i.previouslyReturnedValidators=!1;let v={value:e.target.value,model:a,args:t,arrayAncestors:e.arrayAncestors},y=i.validator(v);if(y instanceof Promise){let R=await y;if(Array.isArray(R)){let P=m(i,R,o),$=await Promise.all(P);p.push(...$.flat()),c&&S(e,i)}else c&&S(e,i),R!=null&&(p.push(R),f(e,i,R))}else if(Array.isArray(y)){let R=m(i,y,o),P=await Promise.all(R);p.push(...P.flat()),c&&S(e,i)}else if(c&&S(e,i),y!=null){if(V&&i.optimized===!1){let R=i.validator,P=D(()=>{let $={value:e.target.value,model:a,args:t,arrayAncestors:e.arrayAncestors};return R($)});i.optimized=!0,i.validator=()=>P.value}p.push(y),f(e,i,y)}return p}function m(i,V,o){let p=w(V,i.isReactive,i.validatorId),c=l(p,o),v=o.spawnedValidators;for(let y of p)v[y.validatorId]!=null&&console.error(`Unable to keep track of nested validators. Validator ID: ${y.validatorId} was not unique.`),v[y.validatorId]=y;return i.spawnedValidators=v,i.previouslyReturnedValidators=!0,c}}function S(e,a){for(let t in a.previouslySpawnedValidators){if(a.spawnedValidators[t]!=null)continue;let n=e.validationResults.value.findIndex(r=>r.id===t);n!==-1&&e.validationResults.value.splice(n,1)}}async function B(e,a,t,n,r){e.isValidatingReactive.value=!0;let s=await j(e,a,t,n,r,e.reactiveProcessedValidators);return n===G(r)&&(e.isReactiveValid.value=s,e.isValidatingReactive.value=!1),e.isReactiveValid.value??!1}async function _(e,a,t,n,r){e.isValidatingLazy.value=!0;let s=await j(e,a,t,n,r,e.lazyProcessedValidators);return n===G(r)&&(e.isLazyValid.value=s,e.isValidatingLazy.value=!1),e.isLazyValid.value??!1}function A(e,a,t,n,r){let s=[];for(let d of e)if(n&&d.reactiveProcessedValidators.length>0&&s.push(B(d,a.value,t,++d.reactiveIterationId,()=>d.reactiveIterationId)),r&&d.lazyProcessedValidators.length>0&&s.push(_(d,a.value,t,++d.lazyIterationId,()=>d.lazyIterationId)),Array.isArray(d.validationState.$arrayState)){let f=[];for(let u in d.arrayConfigMap)f.push(...d.arrayConfigMap[u].validationConfigs);s.push(A(f,a,t,n,r))}return Promise.all(s).then(d=>d.every(f=>f===!0))}function J(e){e.delayReactiveValidation??=!0;let{model:a,validation:t,delayReactiveValidation:n,args:r}=e,s=E(!1),d=h(()=>V.some(v=>v.isValidatingLazy.value||v.isValidatingReactive.value)),f=h(()=>V.some(v=>v.validationResults.value.some(y=>y.isValid===!1))),u=h(()=>V.every(y=>y.isReactiveValid.value&&y.isLazyValid.value)),l=E(JSON.stringify(e.model.value)),g=h(()=>l.value!==JSON.stringify(e.model.value)),m=z(a,t),i=m.state,V=m.validationConfigs;q(e.model,()=>{n?s.value===!0&&A(V,a,r,!0,!1):A(V,a,r,!0,!1)},{deep:!0});async function o(){let v=await A(V,a,r,!0,!0);return s.value=!0,v}function p(v){l.value=JSON.stringify(v)}function c(){s.value=!1,m=z(a,t),V=m.validationConfigs,i=m.state}return U({hasValidated:s,validate:o,isValidating:d,state:h(()=>i),isValid:u,isErrored:f,setReference:p,isDirty:g,reset:c})}export{x as V$_IGNORE,H as bufferAsync,le as exclusiveMaxNumber,oe as exclusiveMinNumber,ce as isEmailSync,ne as maxLength,se as maxNumber,ie as minLength,re as minNumber,de as must,te as notEmpty,O as reduceUndefined,ae as required,Y as throttleAsync,Q as throttleBufferAsync,X as trailingDebounceAsync,J as useValidation,ue as validateIf};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vuelidify",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "author": "Daniel Walbolt",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",