@regle/core 0.0.7 → 0.0.9

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/dist/index.js CHANGED
@@ -202,8 +202,9 @@ function useStorage() {
202
202
  const $pending = ref(false);
203
203
  const $valid = ref(true);
204
204
  const $metadata = ref({});
205
- ruleStatusStorage.value.set(path, { $pending, $valid, $metadata });
206
- return { $pending, $valid, $metadata };
205
+ const $validating = ref(false);
206
+ ruleStatusStorage.value.set(path, { $pending, $valid, $metadata, $validating });
207
+ return { $pending, $valid, $metadata, $validating };
207
208
  }
208
209
  }
209
210
  onScopeDispose(() => {
@@ -265,6 +266,35 @@ function isEmpty(value) {
265
266
  // src/utils/composables.ts
266
267
  import { effectScope, getCurrentScope, onScopeDispose as onScopeDispose2 } from "vue";
267
268
 
269
+ // src/utils/debounce.ts
270
+ function debounce(func, wait, immediate) {
271
+ let timeout;
272
+ const debouncedFn = (...args) => new Promise((resolve) => {
273
+ clearTimeout(timeout);
274
+ timeout = setTimeout(() => {
275
+ timeout = void 0;
276
+ if (!immediate) {
277
+ void Promise.resolve(func.apply(this, [...args])).then(resolve);
278
+ }
279
+ }, wait);
280
+ if (immediate && !timeout) {
281
+ void Promise.resolve(func.apply(this, [...args])).then(resolve);
282
+ }
283
+ });
284
+ debouncedFn.cancel = () => {
285
+ clearTimeout(timeout);
286
+ timeout = void 0;
287
+ };
288
+ debouncedFn.doImmediately = (...args) => new Promise((resolve) => {
289
+ clearTimeout(timeout);
290
+ timeout = setTimeout(() => {
291
+ timeout = void 0;
292
+ void Promise.resolve(func.apply(this, [...args])).then(resolve);
293
+ }, 0);
294
+ });
295
+ return debouncedFn;
296
+ }
297
+
268
298
  // src/core/useRegle/guards/ruleDef.guards.ts
269
299
  function isNestedRulesDef(state, rule) {
270
300
  return isObject(state.value) && isObject(rule.value) && !Object.entries(rule.value).some((rule2) => isRuleDef(rule2));
@@ -305,7 +335,13 @@ function extractRulesErrors(rules, externalErrors) {
305
335
  return rule.$message;
306
336
  }
307
337
  return null;
308
- }).filter((msg) => !!msg).concat(externalErrors ?? []);
338
+ }).filter((msg) => !!msg).reduce((acc, value) => {
339
+ if (typeof value === "string") {
340
+ return acc?.concat([value]);
341
+ } else {
342
+ return acc?.concat(value);
343
+ }
344
+ }, []).concat(externalErrors ?? []);
309
345
  }
310
346
  function processFieldErrors(fieldStatus) {
311
347
  if (isNestedRulesStatus(fieldStatus)) {
@@ -396,7 +432,9 @@ function createReactiveRuleStatus({
396
432
  }) {
397
433
  let scope = effectScope2();
398
434
  let scopeState;
399
- const { $pending, $valid, $metadata } = storage.trySetRuleStatusRef(`${path}.${ruleKey}`);
435
+ const { $pending, $valid, $metadata, $validating } = storage.trySetRuleStatusRef(
436
+ `${path}.${ruleKey}`
437
+ );
400
438
  function $watch() {
401
439
  scopeState = scope.run(() => {
402
440
  const $defaultMetadata = computed2(() => ({
@@ -417,26 +455,28 @@ function createReactiveRuleStatus({
417
455
  });
418
456
  const $message = computed2(() => {
419
457
  let message = "";
420
- const customMessageRule = customMessages ? customMessages[ruleKey]?.message : void 0;
421
- if (customMessageRule) {
422
- if (typeof customMessageRule === "function") {
423
- message = customMessageRule(state.value, $defaultMetadata.value);
424
- } else {
425
- message = customMessageRule;
426
- }
427
- }
428
- if (isFormRuleDefinition(rule)) {
429
- if (!(customMessageRule && !rule.value._patched)) {
430
- if (typeof rule.value.message === "function") {
431
- message = rule.value.message(state.value, $defaultMetadata.value);
458
+ if ($dirty.value && !$validating.value) {
459
+ const customMessageRule = customMessages ? customMessages[ruleKey]?.message : void 0;
460
+ if (customMessageRule) {
461
+ if (typeof customMessageRule === "function") {
462
+ message = customMessageRule(state.value, $defaultMetadata.value);
432
463
  } else {
433
- message = rule.value.message;
464
+ message = customMessageRule;
434
465
  }
435
466
  }
436
- }
437
- if (isEmpty(message)) {
438
- message = "Error";
439
- console.warn(`No error message defined for ${ruleKey}`);
467
+ if (isFormRuleDefinition(rule)) {
468
+ if (!(customMessageRule && !rule.value._patched)) {
469
+ if (typeof rule.value.message === "function") {
470
+ message = rule.value.message(state.value, $defaultMetadata.value);
471
+ } else {
472
+ message = rule.value.message;
473
+ }
474
+ }
475
+ }
476
+ if (isEmpty(message)) {
477
+ message = "Error";
478
+ console.warn(`No error message defined for ${ruleKey}`);
479
+ }
440
480
  }
441
481
  return message;
442
482
  });
@@ -476,43 +516,48 @@ function createReactiveRuleStatus({
476
516
  deep: true
477
517
  });
478
518
  async function $validate() {
479
- const validator = scopeState.$validator.value;
480
- let ruleResult = false;
481
- const resultOrPromise = validator(state.value, ...scopeState.$params.value);
482
- if (resultOrPromise instanceof Promise) {
483
- if ($dirty.value && !$pending.value) {
484
- try {
485
- $valid.value = true;
486
- $pending.value = true;
487
- const promiseResult = await resultOrPromise;
488
- if (typeof promiseResult === "boolean") {
489
- ruleResult = promiseResult;
519
+ try {
520
+ $validating.value = true;
521
+ const validator = scopeState.$validator.value;
522
+ let ruleResult = false;
523
+ const resultOrPromise = validator(state.value, ...scopeState.$params.value);
524
+ if (resultOrPromise instanceof Promise) {
525
+ if ($dirty.value && !$pending.value) {
526
+ try {
527
+ $valid.value = true;
528
+ $pending.value = true;
529
+ const promiseResult = await resultOrPromise;
530
+ if (typeof promiseResult === "boolean") {
531
+ ruleResult = promiseResult;
532
+ } else {
533
+ const { $valid: $valid2, ...rest } = promiseResult;
534
+ ruleResult = $valid2;
535
+ $metadata.value = rest;
536
+ }
537
+ } catch (e) {
538
+ ruleResult = false;
539
+ } finally {
540
+ $pending.value = false;
541
+ }
542
+ }
543
+ } else {
544
+ if (resultOrPromise != null) {
545
+ if (typeof resultOrPromise === "boolean") {
546
+ ruleResult = resultOrPromise;
490
547
  } else {
491
- const { $valid: $valid2, ...rest } = promiseResult;
548
+ const { $valid: $valid2, ...rest } = resultOrPromise;
492
549
  ruleResult = $valid2;
493
550
  $metadata.value = rest;
494
551
  }
495
- } catch (e) {
496
- ruleResult = false;
497
- } finally {
498
- $pending.value = false;
499
552
  }
500
553
  }
501
- } else {
502
- if (resultOrPromise != null) {
503
- if (typeof resultOrPromise === "boolean") {
504
- ruleResult = resultOrPromise;
505
- } else {
506
- const { $valid: $valid2, ...rest } = resultOrPromise;
507
- ruleResult = $valid2;
508
- $metadata.value = rest;
509
- }
554
+ $valid.value = ruleResult;
555
+ if (options.$externalErrors) {
510
556
  }
557
+ return ruleResult;
558
+ } finally {
559
+ $validating.value = false;
511
560
  }
512
- $valid.value = ruleResult;
513
- if (options.$externalErrors) {
514
- }
515
- return ruleResult;
516
561
  }
517
562
  function $unwatch() {
518
563
  $unwatchState();
@@ -555,8 +600,11 @@ function createReactiveFieldStatus({
555
600
  function createReactiveRulesResult() {
556
601
  const declaredRules = rulesDef.value;
557
602
  const storeResult = storage.checkRuleDeclEntry(path, declaredRules);
603
+ $localOptions.value = Object.fromEntries(
604
+ Object.entries(declaredRules).filter(([ruleKey]) => ruleKey.startsWith("$"))
605
+ );
558
606
  $rules.value = Object.fromEntries(
559
- Object.entries(declaredRules).map(([ruleKey, rule]) => {
607
+ Object.entries(declaredRules).filter(([ruleKey]) => !ruleKey.startsWith("$")).map(([ruleKey, rule]) => {
560
608
  if (rule) {
561
609
  const ruleRef = toRef2(() => rule);
562
610
  return [
@@ -589,15 +637,17 @@ function createReactiveFieldStatus({
589
637
  storage.setDirtyEntry(path, $dirty.value);
590
638
  });
591
639
  const $unwatchState = watch2(state, () => {
592
- if (unref2(options.autoDirty)) {
640
+ if (scopeState.$autoDirty.value) {
593
641
  if (!$dirty.value) {
594
642
  $dirty.value = true;
595
643
  }
596
644
  }
597
- if (!unref2(options.lazy)) {
645
+ if (!scopeState.$lazy.value) {
598
646
  $commit();
647
+ if (!scopeState.$rewardEarly.value !== false) {
648
+ $clearExternalErrors();
649
+ }
599
650
  }
600
- $externalErrors.value = [];
601
651
  });
602
652
  function $unwatch() {
603
653
  if ($rules.value) {
@@ -617,11 +667,32 @@ function createReactiveFieldStatus({
617
667
  }
618
668
  function $watch() {
619
669
  scopeState = scope.run(() => {
670
+ const $debounce = computed3(() => {
671
+ return $localOptions.value.$debounce;
672
+ });
673
+ const $lazy = computed3(() => {
674
+ if ($localOptions.value.$lazy) {
675
+ return $localOptions.value.$lazy;
676
+ }
677
+ return unref2(options.lazy);
678
+ });
679
+ const $rewardEarly = computed3(() => {
680
+ if ($localOptions.value.$rewardEarly) {
681
+ return $localOptions.value.$rewardEarly;
682
+ }
683
+ return unref2(options.rewardEarly);
684
+ });
685
+ const $autoDirty = computed3(() => {
686
+ if ($localOptions.value.$autoDirty) {
687
+ return $localOptions.value.$autoDirty;
688
+ }
689
+ return unref2(options.autoDirty);
690
+ });
620
691
  const $error = computed3(() => {
621
692
  return $invalid.value && !$pending.value && $dirty.value;
622
693
  });
623
694
  const $pending = computed3(() => {
624
- if (triggerPunishment.value || !unref2(options.rewardEarly)) {
695
+ if (triggerPunishment.value || !$rewardEarly.value) {
625
696
  return Object.entries($rules.value).some(([key, ruleResult]) => {
626
697
  return ruleResult.$pending;
627
698
  });
@@ -629,7 +700,9 @@ function createReactiveFieldStatus({
629
700
  return false;
630
701
  });
631
702
  const $invalid = computed3(() => {
632
- if (triggerPunishment.value || !unref2(options.rewardEarly)) {
703
+ if ($externalErrors.value?.length) {
704
+ return true;
705
+ } else if (triggerPunishment.value || !$rewardEarly.value) {
633
706
  return Object.entries($rules.value).some(([key, ruleResult]) => {
634
707
  return !ruleResult.$valid;
635
708
  });
@@ -637,7 +710,9 @@ function createReactiveFieldStatus({
637
710
  return false;
638
711
  });
639
712
  const $valid = computed3(() => {
640
- if (unref2(options.rewardEarly)) {
713
+ if ($externalErrors.value?.length) {
714
+ return false;
715
+ } else if ($rewardEarly.value) {
641
716
  return Object.entries($rules.value).every(([key, ruleResult]) => {
642
717
  return ruleResult.$valid;
643
718
  });
@@ -649,14 +724,19 @@ function createReactiveFieldStatus({
649
724
  $error,
650
725
  $pending,
651
726
  $invalid,
652
- $valid
727
+ $valid,
728
+ $debounce,
729
+ $lazy,
730
+ $rewardEarly,
731
+ $autoDirty
653
732
  };
654
733
  });
655
734
  }
656
735
  const $rules = ref2();
736
+ const $localOptions = ref2();
657
737
  createReactiveRulesResult();
658
738
  const $unwatchValid = watch2(scopeState.$valid, (valid) => {
659
- if (unref2(options.rewardEarly) && valid) {
739
+ if (scopeState.$rewardEarly.value && valid) {
660
740
  triggerPunishment.value = false;
661
741
  }
662
742
  });
@@ -667,15 +747,18 @@ function createReactiveFieldStatus({
667
747
  function $touch() {
668
748
  $dirty.value = true;
669
749
  }
670
- function $commit() {
750
+ const $commit = debounce($commitHandler, scopeState.$debounce.value ?? 0);
751
+ function $commitHandler() {
671
752
  Object.entries($rules.value).map(([key, rule]) => {
672
753
  return rule.$validate();
673
754
  });
674
755
  }
675
- async function $validate() {
756
+ const $validate = debounce($validateHandler, scopeState.$debounce.value ?? 0);
757
+ async function $validateHandler() {
676
758
  try {
759
+ $clearExternalErrors();
677
760
  triggerPunishment.value = true;
678
- const results = await Promise.all(
761
+ const results = await Promise.allSettled(
679
762
  Object.entries($rules.value).map(([key, rule]) => {
680
763
  return rule.$validate();
681
764
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@regle/core",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Vue form validator",
5
5
  "scripts": {
6
6
  "lint": "eslint --ext .ts --ext .vue .",