@arsedizioni/ars-utils 22.5.28 → 22.5.32
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 +15 -12
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +17 -6
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.validators.mjs +472 -113
- package/fesm2022/arsedizioni-ars-utils-core.validators.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs +21 -15
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs +322 -3
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs +27 -12
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs +6 -4
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.files.mjs +12 -16
- package/fesm2022/arsedizioni-ars-utils-ui.files.mjs.map +1 -1
- package/package.json +1 -5
- package/types/arsedizioni-ars-utils-clipper.ui.d.ts +18 -2
- package/types/arsedizioni-ars-utils-core.validators.d.ts +218 -52
- package/types/arsedizioni-ars-utils-ui.dialogs.auth.d.ts +7 -0
- package/types/arsedizioni-ars-utils-ui.dialogs.d.ts +119 -1
- package/types/arsedizioni-ars-utils-ui.dialogs.prompt.d.ts +20 -0
- package/types/arsedizioni-ars-utils-ui.dialogs.select.d.ts +3 -0
- package/types/arsedizioni-ars-utils-ui.files.d.ts +3 -0
- package/ui.application/package.json +4 -0
|
@@ -702,118 +702,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
702
702
|
}] });
|
|
703
703
|
|
|
704
704
|
/**
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
* `time`, `equals`) are ignored. Schemas built with `form()` must therefore use these
|
|
710
|
-
* functions instead. Error kinds and messages match the directive versions one to one.
|
|
711
|
-
*/
|
|
712
|
-
/**
|
|
713
|
-
* Binds a validator requiring the value to be a semicolon-separated list of valid
|
|
714
|
-
* email addresses. An empty value is considered valid (pair with `required` if needed).
|
|
715
|
-
* Signal-forms counterpart of `EmailsValidatorDirective`.
|
|
716
|
-
* @param path - Path of the string field to validate.
|
|
717
|
-
*/
|
|
718
|
-
function emailsValidator(path) {
|
|
719
|
-
validate(path, ({ value }) => {
|
|
720
|
-
const input = value();
|
|
721
|
-
if (!input || input.length === 0)
|
|
722
|
-
return undefined;
|
|
723
|
-
const parts = input.replaceAll(/\r\n/g, '').split(';');
|
|
724
|
-
const isValid = parts.every(part => part.length === 0 || !!SystemUtils.parseEmail(part));
|
|
725
|
-
return isValid ? undefined : { kind: 'emails', message: 'Elenco non valido.' };
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
/**
|
|
729
|
-
* Binds a validator requiring the value to meet the minimum password-strength
|
|
730
|
-
* requirements (see `SystemUtils.calculatePasswordStrength`). An empty value is
|
|
731
|
-
* INVALID, exactly like the classic directive.
|
|
732
|
-
* Signal-forms counterpart of `PasswordValidatorDirective`.
|
|
733
|
-
* @param path - Path of the string field to validate.
|
|
705
|
+
* Default texts of the rules declared here, in one place so that the validators and the fallback
|
|
706
|
+
* map of `SignalsUtils.getFieldErrorMessage` cannot drift apart: a rule added below without a
|
|
707
|
+
* message here would show "Errore", and one renamed here without touching the validator would
|
|
708
|
+
* leave the map with a kind nobody produces.
|
|
734
709
|
*/
|
|
735
|
-
function passwordValidator(path) {
|
|
736
|
-
validate(path, ({ value }) => {
|
|
737
|
-
const strength = SystemUtils.calculatePasswordStrength(value() ?? '');
|
|
738
|
-
return strength.isValid ? undefined : { kind: 'password', message: 'Non valido.' };
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
710
|
/**
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
* ranges (e.g. `"08:00-12:00|14:00-18:00"`), or `undefined` for none.
|
|
749
|
-
*/
|
|
750
|
-
function timeValidator(path, slots) {
|
|
751
|
-
/**
|
|
752
|
-
* Parses a `"HH:MM"` time string into a comparable integer (e.g. `"09:30"` -> `930`).
|
|
753
|
-
* Returns `-1` when the string is not a valid time.
|
|
754
|
-
* @param value - The time string to parse.
|
|
755
|
-
* @returns The comparable integer, or `-1` when invalid.
|
|
756
|
-
*/
|
|
757
|
-
const getTime = (value) => {
|
|
758
|
-
const p = value.split(':');
|
|
759
|
-
if (p.length !== 2)
|
|
760
|
-
return -1;
|
|
761
|
-
const hh = parseInt(p[0], 10);
|
|
762
|
-
if (isNaN(hh) || hh < 0 || hh > 23)
|
|
763
|
-
return -1;
|
|
764
|
-
const mm = parseInt(p[1], 10);
|
|
765
|
-
if (isNaN(mm) || mm < 0 || mm > 59)
|
|
766
|
-
return -1;
|
|
767
|
-
return hh * 100 + mm;
|
|
768
|
-
};
|
|
769
|
-
validate(path, ({ value }) => {
|
|
770
|
-
const input = value();
|
|
771
|
-
if (!input || input.length === 0)
|
|
772
|
-
return undefined;
|
|
773
|
-
const t = getTime(input);
|
|
774
|
-
if (t === -1)
|
|
775
|
-
return { kind: 'time', message: 'Non valido.' };
|
|
776
|
-
const slotsValue = slots?.();
|
|
777
|
-
if (slotsValue) {
|
|
778
|
-
const isValid = slotsValue.split('|').some(s => {
|
|
779
|
-
const t1 = getTime(s.substring(0, 5));
|
|
780
|
-
const t2 = getTime(s.substring(6));
|
|
781
|
-
return t1 !== -1 && t2 !== -1 && t1 <= t && t2 >= t;
|
|
782
|
-
});
|
|
783
|
-
if (!isValid)
|
|
784
|
-
return { kind: 'time', message: 'Non valido.' };
|
|
785
|
-
}
|
|
786
|
-
return undefined;
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* Binds a validator requiring the value to strictly equal the value of another field
|
|
791
|
-
* of the same form. Reactive on both fields, so the host field re-validates when the
|
|
792
|
-
* other field changes (this replaces the `valueChanges` subscription of the directive).
|
|
793
|
-
* Signal-forms counterpart of `EqualsValidatorDirective`.
|
|
794
|
-
* @param path - Path of the field to validate.
|
|
795
|
-
* @param other - Path of the field whose value must match.
|
|
796
|
-
*/
|
|
797
|
-
function equalsValidator(path, other) {
|
|
798
|
-
validate(path, ctx => ctx.valueOf(other) === ctx.value()
|
|
799
|
-
? undefined
|
|
800
|
-
: { kind: 'equals', message: 'Non valido.' });
|
|
801
|
-
}
|
|
802
|
-
/**
|
|
803
|
-
* Binds a validator requiring the value to be either empty or a complete 6-digit
|
|
804
|
-
* OTP code. A partial code (e.g. `"12"`) is invalid; emptiness is left to `required`.
|
|
805
|
-
* Schema-level counterpart of the `OtpInputComponent` internal validator.
|
|
806
|
-
* @param path - Path of the string field to validate.
|
|
711
|
+
* Earliest date {@link date} and {@link dateRange} accept: 1 January 1970.
|
|
712
|
+
*
|
|
713
|
+
* Everything this application stores — events, certificates, payments, communications — happened
|
|
714
|
+
* after it, so an earlier value is always a typo (a two-digit year, a slipped keystroke) and never
|
|
715
|
+
* real data. The floor is deliberately higher than the one of {@link sqlDate}, which only asks
|
|
716
|
+
* what SQL Server can physically store.
|
|
807
717
|
*/
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
718
|
+
const MIN_VALID_YEAR = 1970;
|
|
719
|
+
const ARS_VALIDATOR_MESSAGES = {
|
|
720
|
+
guid: 'Ticket non riconosciuto',
|
|
721
|
+
password: 'Password non sufficientemente robusta',
|
|
722
|
+
notEmpty: 'Non può contenere solo spazi',
|
|
723
|
+
notEqual: 'Deve essere diverso dall\'altro valore',
|
|
724
|
+
sqlDate: 'Data non valida',
|
|
725
|
+
date: 'Data non valida',
|
|
726
|
+
dateRange: 'Intervallo non valido',
|
|
727
|
+
notFuture: 'La data non può essere futura',
|
|
728
|
+
url: 'Indirizzo non valido',
|
|
729
|
+
maxTerms: 'Troppe parole',
|
|
730
|
+
fileSize: 'Dimensione del file non ammessa',
|
|
731
|
+
validIf: 'Non valido',
|
|
732
|
+
emails: 'Elenco non valido',
|
|
733
|
+
time: 'Orario non valido',
|
|
734
|
+
equals: 'I due valori non coincidono',
|
|
735
|
+
otp: 'Codice non valido',
|
|
736
|
+
};
|
|
817
737
|
/**
|
|
818
738
|
* Requires the value to be a well-formed GUID / UUID.
|
|
819
739
|
*
|
|
@@ -836,7 +756,7 @@ function guid(path, config) {
|
|
|
836
756
|
return null;
|
|
837
757
|
return SystemUtils.parseUUID(input)
|
|
838
758
|
? null
|
|
839
|
-
: { kind: 'guid', message: config?.message ?? '
|
|
759
|
+
: { kind: 'guid', message: config?.message ?? ARS_VALIDATOR_MESSAGES['guid'] };
|
|
840
760
|
});
|
|
841
761
|
}
|
|
842
762
|
/**
|
|
@@ -856,7 +776,7 @@ function password(path, config) {
|
|
|
856
776
|
const strength = SystemUtils.calculatePasswordStrength(ctx.value() ?? '');
|
|
857
777
|
return strength.isValid
|
|
858
778
|
? null
|
|
859
|
-
: { kind: 'password', message: config?.message ?? '
|
|
779
|
+
: { kind: 'password', message: config?.message ?? ARS_VALIDATOR_MESSAGES['password'] };
|
|
860
780
|
});
|
|
861
781
|
}
|
|
862
782
|
/**
|
|
@@ -885,9 +805,448 @@ function notEmpty(path, config) {
|
|
|
885
805
|
return null;
|
|
886
806
|
return input.trim().length > 0
|
|
887
807
|
? null
|
|
888
|
-
: { kind: 'notEmpty', message: config?.message ?? '
|
|
808
|
+
: { kind: 'notEmpty', message: config?.message ?? ARS_VALIDATOR_MESSAGES['notEmpty'] };
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Requires the value to differ from the value of another field of the same form.
|
|
813
|
+
*
|
|
814
|
+
* The signal-form counterpart of `NotEqualValidatorDirective`, with its exact rule: two empty
|
|
815
|
+
* values are considered different, so an untouched pair of fields does not start out in error.
|
|
816
|
+
* Reactive on both fields — editing either one re-validates this one, which is what the
|
|
817
|
+
* directive needed a `valueChanges` subscription (and a re-entrancy guard) to achieve.
|
|
818
|
+
*
|
|
819
|
+
* @param path - Path of the field to validate.
|
|
820
|
+
* @param other - Path of the field whose value must differ.
|
|
821
|
+
* @param config - Optional message override and `when` condition.
|
|
822
|
+
* @returns void
|
|
823
|
+
*/
|
|
824
|
+
function notEqual(path, other, config) {
|
|
825
|
+
validate(path, ctx => {
|
|
826
|
+
if (config?.when && !config.when(ctx))
|
|
827
|
+
return null;
|
|
828
|
+
const mine = ctx.value();
|
|
829
|
+
const theirs = ctx.valueOf(other);
|
|
830
|
+
const isValid = (!theirs && !mine) || theirs !== mine;
|
|
831
|
+
return isValid ? null : { kind: 'notEqual', message: config?.message ?? ARS_VALIDATOR_MESSAGES['notEqual'] };
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Requires the value to be a date the backend can store: parseable, and after 1750.
|
|
836
|
+
*
|
|
837
|
+
* The signal-form counterpart of `SqlDateValidatorDirective`. The year floor is not arbitrary —
|
|
838
|
+
* it is what separates a real date from the 01/01/0001 that a mistyped year produces, which SQL
|
|
839
|
+
* Server rejects with an error nobody can read.
|
|
840
|
+
*
|
|
841
|
+
* @param path - Path of the field to validate.
|
|
842
|
+
* @param config - Optional message override and `when` condition.
|
|
843
|
+
* @returns void
|
|
844
|
+
*/
|
|
845
|
+
function sqlDate(path, config) {
|
|
846
|
+
validate(path, ctx => {
|
|
847
|
+
if (config?.when && !config.when(ctx))
|
|
848
|
+
return null;
|
|
849
|
+
const input = ctx.value();
|
|
850
|
+
if (!input || input.length === 0)
|
|
851
|
+
return null;
|
|
852
|
+
const parsed = SystemUtils.parseDate(input);
|
|
853
|
+
const invalid = { kind: 'sqlDate', message: config?.message ?? ARS_VALIDATOR_MESSAGES['sqlDate'] };
|
|
854
|
+
if (!parsed)
|
|
855
|
+
return invalid;
|
|
856
|
+
return endOfDay(parsed).getFullYear() > 1750 ? null : invalid;
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Requires the value to be a real date, as {@link SystemUtils.parseDate} understands one.
|
|
861
|
+
*
|
|
862
|
+
* This is the rule for anything a user picks or types as a date: it accepts both the `Date` a
|
|
863
|
+
* Material datepicker or timepicker writes into the model and the text of a plain input, since
|
|
864
|
+
* `parseDate` handles the shapes this codebase produces (ISO, `dd/MM/yyyy`, `yyyy-MM-dd`, and the
|
|
865
|
+
* shorthand forms). Empty passes — saying "obbligatorio" is the job of `required()`.
|
|
866
|
+
*
|
|
867
|
+
* A date earlier than {@link MIN_VALID_YEAR} (1 January 1970) is rejected: nothing this
|
|
868
|
+
* application stores predates it, so an earlier value is a typo rather than data.
|
|
869
|
+
*
|
|
870
|
+
* Distinct from {@link sqlDate} on purpose: that one is about what the DATABASE can store (the
|
|
871
|
+
* 1750 floor), this one is about whether the value is a date at all. Pair them when both matter.
|
|
872
|
+
*
|
|
873
|
+
* @param path - Path of the field to validate.
|
|
874
|
+
* @param config - Optional message override and `when` condition.
|
|
875
|
+
* @returns void
|
|
876
|
+
* @example
|
|
877
|
+
* const f = form(this.model, p => { required(p.expiry); date(p.expiry); });
|
|
878
|
+
*/
|
|
879
|
+
function date(path, config) {
|
|
880
|
+
validate(path, ctx => {
|
|
881
|
+
if (config?.when && !config.when(ctx))
|
|
882
|
+
return null;
|
|
883
|
+
const input = ctx.value();
|
|
884
|
+
if (input === undefined || input === null || input === '')
|
|
885
|
+
return null;
|
|
886
|
+
const parsed = SystemUtils.parseDate(input);
|
|
887
|
+
return parsed && parsed.getFullYear() >= MIN_VALID_YEAR
|
|
888
|
+
? null
|
|
889
|
+
: { kind: 'date', message: config?.message ?? ARS_VALIDATOR_MESSAGES['date'] };
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Requires the two ends of a date range to be real dates and to be in order.
|
|
894
|
+
*
|
|
895
|
+
* Written for the two inputs of a `mat-date-range-input`, whose start and end live in two
|
|
896
|
+
* separate fields of the model. Each end is checked with the same rule as {@link date}, and the
|
|
897
|
+
* ordering is checked only when BOTH ends are filled in — a half-open range ("from today
|
|
898
|
+
* onwards") is a legitimate filter, not an error. The 1 January 1970 floor of {@link date}
|
|
899
|
+
* applies to both ends.
|
|
900
|
+
*
|
|
901
|
+
* The rule is bound to BOTH paths, so the error appears on whichever end the user is looking at
|
|
902
|
+
* and a single `<mat-error>` under the range can read either one. Comparison is made on the end
|
|
903
|
+
* of the day, so picking the same day for both ends is valid.
|
|
904
|
+
*
|
|
905
|
+
* @param from - Path of the field holding the start of the range.
|
|
906
|
+
* @param to - Path of the field holding the end of the range.
|
|
907
|
+
* @param config - Optional message override (used for the ordering error) and `when` condition.
|
|
908
|
+
* @returns void
|
|
909
|
+
* @example
|
|
910
|
+
* const f = form(this.model, p => { dateRange(p.sentFrom, p.sentTo); });
|
|
911
|
+
*/
|
|
912
|
+
function dateRange(from, to, config) {
|
|
913
|
+
date(from, config);
|
|
914
|
+
date(to, config);
|
|
915
|
+
/**
|
|
916
|
+
* Compares the two ends of the range once both of them are filled in.
|
|
917
|
+
* @param startValue - Raw value of the start field.
|
|
918
|
+
* @param endValue - Raw value of the end field.
|
|
919
|
+
* @returns The ordering error, or `null` when the pair is acceptable.
|
|
920
|
+
*/
|
|
921
|
+
const checkOrder = (startValue, endValue) => {
|
|
922
|
+
const start = SystemUtils.parseDate(startValue ?? undefined);
|
|
923
|
+
const end = SystemUtils.parseDate(endValue ?? undefined);
|
|
924
|
+
// A half-open range is legitimate: nothing to compare until both ends are there. An end that
|
|
925
|
+
// is not a valid date is already reported by the `date` rule bound above, so it is skipped
|
|
926
|
+
// here rather than reported twice.
|
|
927
|
+
if (!start || !end)
|
|
928
|
+
return null;
|
|
929
|
+
if (start.getFullYear() < MIN_VALID_YEAR || end.getFullYear() < MIN_VALID_YEAR)
|
|
930
|
+
return null;
|
|
931
|
+
return endOfDay(start) <= endOfDay(end)
|
|
932
|
+
? null
|
|
933
|
+
: { kind: 'dateRange', message: config?.message ?? ARS_VALIDATOR_MESSAGES['dateRange'] };
|
|
934
|
+
};
|
|
935
|
+
// Reading the opposite end through `valueOf` keeps each rule reactive on the other field, so
|
|
936
|
+
// filling in one end re-validates the other.
|
|
937
|
+
validate(from, ctx => {
|
|
938
|
+
if (config?.when && !config.when(ctx))
|
|
939
|
+
return null;
|
|
940
|
+
return checkOrder(ctx.value(), ctx.valueOf(to));
|
|
941
|
+
});
|
|
942
|
+
validate(to, ctx => {
|
|
943
|
+
if (config?.when && !config.when(ctx))
|
|
944
|
+
return null;
|
|
945
|
+
return checkOrder(ctx.valueOf(from), ctx.value());
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Requires the value to be a date that is not in the future.
|
|
950
|
+
*
|
|
951
|
+
* The signal-form counterpart of `NotFutureValidatorDirective`. Today counts as valid: the
|
|
952
|
+
* comparison is made on the end of the day, so a date entered this morning does not become
|
|
953
|
+
* invalid because the clock says 09:00.
|
|
954
|
+
*
|
|
955
|
+
* @param path - Path of the field to validate.
|
|
956
|
+
* @param config - Optional message override and `when` condition.
|
|
957
|
+
* @returns void
|
|
958
|
+
*/
|
|
959
|
+
function notFuture(path, config) {
|
|
960
|
+
validate(path, ctx => {
|
|
961
|
+
if (config?.when && !config.when(ctx))
|
|
962
|
+
return null;
|
|
963
|
+
const input = ctx.value();
|
|
964
|
+
if (!input || input.length === 0)
|
|
965
|
+
return null;
|
|
966
|
+
const parsed = SystemUtils.parseDate(input);
|
|
967
|
+
const invalid = { kind: 'notFuture', message: config?.message ?? ARS_VALIDATOR_MESSAGES['notFuture'] };
|
|
968
|
+
if (!parsed)
|
|
969
|
+
return invalid;
|
|
970
|
+
return endOfDay(parsed) <= endOfDay(new Date()) ? null : invalid;
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Requires the value to be a well-formed URL. An empty value passes, as everywhere else here.
|
|
975
|
+
*
|
|
976
|
+
* The signal-form counterpart of `UrlValidatorDirective`.
|
|
977
|
+
*
|
|
978
|
+
* @param path - Path of the field to validate.
|
|
979
|
+
* @param config - Optional message override and `when` condition.
|
|
980
|
+
* @returns void
|
|
981
|
+
*/
|
|
982
|
+
function url(path, config) {
|
|
983
|
+
validate(path, ctx => {
|
|
984
|
+
if (config?.when && !config.when(ctx))
|
|
985
|
+
return null;
|
|
986
|
+
const input = ctx.value();
|
|
987
|
+
if (!input || input.length === 0)
|
|
988
|
+
return null;
|
|
989
|
+
return SystemUtils.parseUrl(input)
|
|
990
|
+
? null
|
|
991
|
+
: { kind: 'url', message: config?.message ?? ARS_VALIDATOR_MESSAGES['url'] };
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Requires the value to hold no more than `max` whitespace-separated terms.
|
|
996
|
+
*
|
|
997
|
+
* The signal-form counterpart of `MaxTermsValidatorDirective`, used on the search boxes where
|
|
998
|
+
* the backend refuses a query past a certain number of words.
|
|
999
|
+
*
|
|
1000
|
+
* @param path - Path of the field to validate.
|
|
1001
|
+
* @param max - The maximum number of terms, as a number or a reactive function.
|
|
1002
|
+
* @param config - Optional message override and `when` condition.
|
|
1003
|
+
* @returns void
|
|
1004
|
+
*/
|
|
1005
|
+
function maxTerms(path, max, config) {
|
|
1006
|
+
validate(path, ctx => {
|
|
1007
|
+
if (config?.when && !config.when(ctx))
|
|
1008
|
+
return null;
|
|
1009
|
+
const input = ctx.value();
|
|
1010
|
+
if (!input)
|
|
1011
|
+
return null;
|
|
1012
|
+
const terms = input.match(/\S+/g)?.length ?? 0;
|
|
1013
|
+
return terms <= (typeof max === 'function' ? max() : max)
|
|
1014
|
+
? null
|
|
1015
|
+
: { kind: 'maxTerms', message: config?.message ?? ARS_VALIDATOR_MESSAGES['maxTerms'] };
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Requires the size of the picked file to fall within the allowed range.
|
|
1020
|
+
*
|
|
1021
|
+
* The signal-form counterpart of `FileSizeValidatorDirective`, and it keeps its shape: the field
|
|
1022
|
+
* itself holds the file NAME, while the size arrives from outside — the control that picked the
|
|
1023
|
+
* file knows it, the form does not. An empty field passes, so "no file" is `required()`'s call
|
|
1024
|
+
* and not a size error.
|
|
1025
|
+
*
|
|
1026
|
+
* @param path - Path of the field holding the file name.
|
|
1027
|
+
* @param sizeMb - The size of the picked file in megabytes, as a reactive function.
|
|
1028
|
+
* @param maxSizeMb - The maximum allowed size in megabytes. Defaults to `5`.
|
|
1029
|
+
* @param minSizeMb - The minimum required size in megabytes. Defaults to `0`.
|
|
1030
|
+
* @param config - Optional message override and `when` condition.
|
|
1031
|
+
* @returns void
|
|
1032
|
+
*/
|
|
1033
|
+
function fileSize(path, sizeMb, maxSizeMb = 5, minSizeMb = 0, config) {
|
|
1034
|
+
validate(path, ctx => {
|
|
1035
|
+
if (config?.when && !config.when(ctx))
|
|
1036
|
+
return null;
|
|
1037
|
+
if (!ctx.value())
|
|
1038
|
+
return null;
|
|
1039
|
+
const size = sizeMb() ?? 0;
|
|
1040
|
+
const max = typeof maxSizeMb === 'function' ? maxSizeMb() : maxSizeMb;
|
|
1041
|
+
const min = typeof minSizeMb === 'function' ? minSizeMb() : minSizeMb;
|
|
1042
|
+
return size <= max && size >= min
|
|
1043
|
+
? null
|
|
1044
|
+
: { kind: 'fileSize', message: config?.message ?? ARS_VALIDATOR_MESSAGES['fileSize'] };
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Requires the value to declare itself valid.
|
|
1049
|
+
*
|
|
1050
|
+
* The signal-form counterpart of `ValidIfDirective`: when the field holds an object implementing
|
|
1051
|
+
* `Validated` the verdict is its own `isValid()`, and when the field is empty the verdict is the
|
|
1052
|
+
* `flag`. It is the escape hatch for the composite controls whose validity only they can judge.
|
|
1053
|
+
*
|
|
1054
|
+
* @param path - Path of the field to validate.
|
|
1055
|
+
* @param flag - Verdict used while the field is empty, as a boolean or a reactive function.
|
|
1056
|
+
* Defaults to `false`.
|
|
1057
|
+
* @param config - Optional message override and `when` condition.
|
|
1058
|
+
* @returns void
|
|
1059
|
+
*/
|
|
1060
|
+
function validIf(path, flag = false, config) {
|
|
1061
|
+
validate(path, ctx => {
|
|
1062
|
+
if (config?.when && !config.when(ctx))
|
|
1063
|
+
return null;
|
|
1064
|
+
const value = ctx.value();
|
|
1065
|
+
let isValid;
|
|
1066
|
+
if (!value) {
|
|
1067
|
+
isValid = (typeof flag === 'function' ? flag() : flag) === true;
|
|
1068
|
+
}
|
|
1069
|
+
else {
|
|
1070
|
+
try {
|
|
1071
|
+
isValid = value.isValid?.() === true;
|
|
1072
|
+
}
|
|
1073
|
+
catch {
|
|
1074
|
+
isValid = false;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return isValid ? null : { kind: 'validIf', message: config?.message ?? ARS_VALIDATOR_MESSAGES['validIf'] };
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Requires the value to be a semicolon-separated list of valid e-mail addresses.
|
|
1082
|
+
*
|
|
1083
|
+
* The signal-form counterpart of `EmailsValidatorDirective`. An empty value passes, and so does
|
|
1084
|
+
* an empty entry between two semicolons: the list is typed by hand and a trailing `;` is not a
|
|
1085
|
+
* mistake worth an error.
|
|
1086
|
+
*
|
|
1087
|
+
* @param path - Path of the field to validate.
|
|
1088
|
+
* @param config - Optional message override and `when` condition.
|
|
1089
|
+
* @returns void
|
|
1090
|
+
*/
|
|
1091
|
+
function emails(path, config) {
|
|
1092
|
+
validate(path, ctx => {
|
|
1093
|
+
if (config?.when && !config.when(ctx))
|
|
1094
|
+
return null;
|
|
1095
|
+
const input = ctx.value();
|
|
1096
|
+
if (!input || input.length === 0)
|
|
1097
|
+
return null;
|
|
1098
|
+
const parts = input.replaceAll(/\r\n/g, '').split(';');
|
|
1099
|
+
const isValid = parts.every(part => part.length === 0 || !!SystemUtils.parseEmail(part));
|
|
1100
|
+
return isValid ? null : { kind: 'emails', message: config?.message ?? ARS_VALIDATOR_MESSAGES['emails'] };
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Requires the value to be a `"HH:MM"` time and, when slots are given, to fall inside one of them.
|
|
1105
|
+
*
|
|
1106
|
+
* The signal-form counterpart of `TimeValidatorDirective`. An empty value passes.
|
|
1107
|
+
*
|
|
1108
|
+
* @param path - Path of the field to validate.
|
|
1109
|
+
* @param slots - Optional reactive function returning the pipe-separated allowed ranges
|
|
1110
|
+
* (e.g. `"08:00-12:00|14:00-18:00"`), or `undefined` for no restriction.
|
|
1111
|
+
* @param config - Optional message override and `when` condition.
|
|
1112
|
+
* @returns void
|
|
1113
|
+
*/
|
|
1114
|
+
function time(path, slots, config) {
|
|
1115
|
+
/**
|
|
1116
|
+
* Turns `"HH:MM"` into a comparable integer (`"09:30"` -> `930`).
|
|
1117
|
+
* @param value - The time string to parse.
|
|
1118
|
+
* @returns The comparable integer, or `-1` when the string is not a valid time.
|
|
1119
|
+
*/
|
|
1120
|
+
const getTime = (value) => {
|
|
1121
|
+
const p = value.split(':');
|
|
1122
|
+
if (p.length !== 2)
|
|
1123
|
+
return -1;
|
|
1124
|
+
const hh = parseInt(p[0], 10);
|
|
1125
|
+
if (isNaN(hh) || hh < 0 || hh > 23)
|
|
1126
|
+
return -1;
|
|
1127
|
+
const mm = parseInt(p[1], 10);
|
|
1128
|
+
if (isNaN(mm) || mm < 0 || mm > 59)
|
|
1129
|
+
return -1;
|
|
1130
|
+
return hh * 100 + mm;
|
|
1131
|
+
};
|
|
1132
|
+
validate(path, ctx => {
|
|
1133
|
+
if (config?.when && !config.when(ctx))
|
|
1134
|
+
return null;
|
|
1135
|
+
const input = ctx.value();
|
|
1136
|
+
if (!input || input.length === 0)
|
|
1137
|
+
return null;
|
|
1138
|
+
const invalid = { kind: 'time', message: config?.message ?? ARS_VALIDATOR_MESSAGES['time'] };
|
|
1139
|
+
const t = getTime(input);
|
|
1140
|
+
if (t === -1)
|
|
1141
|
+
return invalid;
|
|
1142
|
+
const slotsValue = slots?.();
|
|
1143
|
+
if (slotsValue) {
|
|
1144
|
+
const inSlot = slotsValue.split('|').some(s => {
|
|
1145
|
+
const from = getTime(s.substring(0, 5));
|
|
1146
|
+
const to = getTime(s.substring(6));
|
|
1147
|
+
return from !== -1 && to !== -1 && from <= t && to >= t;
|
|
1148
|
+
});
|
|
1149
|
+
if (!inSlot)
|
|
1150
|
+
return invalid;
|
|
1151
|
+
}
|
|
1152
|
+
return null;
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Requires the value to equal the value of another field of the same form.
|
|
1157
|
+
*
|
|
1158
|
+
* The signal-form counterpart of `EqualsValidatorDirective`. Reactive on both fields, which is
|
|
1159
|
+
* what the directive needed a `valueChanges` subscription to obtain: retyping the first password
|
|
1160
|
+
* re-validates the confirmation without anyone wiring the two together.
|
|
1161
|
+
*
|
|
1162
|
+
* @param path - Path of the field to validate.
|
|
1163
|
+
* @param other - Path of the field whose value must match.
|
|
1164
|
+
* @param config - Optional message override and `when` condition.
|
|
1165
|
+
* @returns void
|
|
1166
|
+
*/
|
|
1167
|
+
function equals(path, other, config) {
|
|
1168
|
+
validate(path, ctx => {
|
|
1169
|
+
if (config?.when && !config.when(ctx))
|
|
1170
|
+
return null;
|
|
1171
|
+
return ctx.valueOf(other) === ctx.value()
|
|
1172
|
+
? null
|
|
1173
|
+
: { kind: 'equals', message: config?.message ?? ARS_VALIDATOR_MESSAGES['equals'] };
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Requires the value to be either empty or a complete six-digit one-time code.
|
|
1178
|
+
*
|
|
1179
|
+
* The schema-level counterpart of the validator inside `OtpInputComponent`: a partial code is an
|
|
1180
|
+
* error, an empty one is `required()`'s business.
|
|
1181
|
+
*
|
|
1182
|
+
* @param path - Path of the field to validate.
|
|
1183
|
+
* @param config - Optional message override and `when` condition.
|
|
1184
|
+
* @returns void
|
|
1185
|
+
*/
|
|
1186
|
+
function otp(path, config) {
|
|
1187
|
+
validate(path, ctx => {
|
|
1188
|
+
if (config?.when && !config.when(ctx))
|
|
1189
|
+
return null;
|
|
1190
|
+
const input = ctx.value() ?? '';
|
|
1191
|
+
if (input.length === 0)
|
|
1192
|
+
return null;
|
|
1193
|
+
return /^\d{6}$/.test(input)
|
|
1194
|
+
? null
|
|
1195
|
+
: { kind: 'otp', message: config?.message ?? ARS_VALIDATOR_MESSAGES['otp'] };
|
|
889
1196
|
});
|
|
890
1197
|
}
|
|
1198
|
+
/** Helpers around signal forms that are not validators themselves. */
|
|
1199
|
+
class SignalsUtils {
|
|
1200
|
+
/**
|
|
1201
|
+
* Builds the error text for a signal-forms field.
|
|
1202
|
+
*
|
|
1203
|
+
* Deliberately dumb: the wording lives in the schema, next to the rule that produces it
|
|
1204
|
+
* (`required(p.x, { message: ... })`), so a field says what is wrong with it in one place
|
|
1205
|
+
* instead of here in a switch that has to guess from the error kind. The map below is only
|
|
1206
|
+
* the safety net for the rules declared without a message — the Angular built-ins, plus
|
|
1207
|
+
* {@link ARS_VALIDATOR_MESSAGES} for the ones declared in this file.
|
|
1208
|
+
* @param errors - The errors currently on the field, from `f.x().errors()`.
|
|
1209
|
+
* @param message - Optional override applied to every error of the field.
|
|
1210
|
+
* @returns The first relevant error text, or `undefined` when the field has no errors.
|
|
1211
|
+
*/
|
|
1212
|
+
static getFieldErrorMessage(errors, message) {
|
|
1213
|
+
if (!errors || errors.length === 0)
|
|
1214
|
+
return undefined;
|
|
1215
|
+
const fallback = {
|
|
1216
|
+
// Angular built-ins declared without a message of their own.
|
|
1217
|
+
required: 'Obbligatorio',
|
|
1218
|
+
min: 'Valore troppo basso',
|
|
1219
|
+
max: 'Valore troppo alto',
|
|
1220
|
+
minLength: 'Testo troppo corto',
|
|
1221
|
+
maxLength: 'Testo troppo lungo',
|
|
1222
|
+
pattern: 'Formato non valido',
|
|
1223
|
+
email: 'Indirizzo email non valido',
|
|
1224
|
+
minDate: 'Data troppo indietro',
|
|
1225
|
+
maxDate: 'Data troppo avanti',
|
|
1226
|
+
parse: 'Valore non valido',
|
|
1227
|
+
// Material's own date/time controls. They validate through NG_VALIDATORS, which the
|
|
1228
|
+
// `[formField]` directive honours on a ControlValueAccessor host, and the interop turns
|
|
1229
|
+
// each legacy key into a `CompatValidationError` carrying the key as `kind` and NO
|
|
1230
|
+
// message — so without these entries an unparseable date reads "Non valido", and the
|
|
1231
|
+
// message declared on the schema rule never gets a say because the parse error comes
|
|
1232
|
+
// first and the field value is `null` (which every rule here treats as empty).
|
|
1233
|
+
matDatepickerParse: 'Data non valida',
|
|
1234
|
+
matDatepickerMin: 'Data troppo indietro',
|
|
1235
|
+
matDatepickerMax: 'Data troppo avanti',
|
|
1236
|
+
matDatepickerFilter: 'Data non selezionabile',
|
|
1237
|
+
matStartDateInvalid: 'Intervallo non valido',
|
|
1238
|
+
matEndDateInvalid: 'Intervallo non valido',
|
|
1239
|
+
matTimepickerParse: 'Orario non valido',
|
|
1240
|
+
matTimepickerMin: 'Orario troppo presto',
|
|
1241
|
+
matTimepickerMax: 'Orario troppo tardi',
|
|
1242
|
+
// The rules of this file, from the single table above: adding a validator there is enough,
|
|
1243
|
+
// and this map can never fall behind it.
|
|
1244
|
+
...ARS_VALIDATOR_MESSAGES,
|
|
1245
|
+
};
|
|
1246
|
+
message = message ?? errors[0].message ?? fallback[errors[0].kind] ?? '';
|
|
1247
|
+
return message.length > 0 ? message : 'Non valido';
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
891
1250
|
|
|
892
1251
|
/*
|
|
893
1252
|
* Public API Surface of @arsedizioni/ars-utils/core.validators
|
|
@@ -902,5 +1261,5 @@ function notEmpty(path, config) {
|
|
|
902
1261
|
* Generated bundle index. Do not edit.
|
|
903
1262
|
*/
|
|
904
1263
|
|
|
905
|
-
export { EmailsValidatorDirective, EqualsValidatorDirective, FileSizeValidatorDirective, GuidValidatorDirective, MaxTermsValidatorDirective, NotEmptyValidatorDirective, NotEqualValidatorDirective, NotFutureValidatorDirective, PasswordValidatorDirective, SqlDateValidatorDirective, TimeValidatorDirective, UrlValidatorDirective, ValidIfDirective, ValidatorDirective,
|
|
1264
|
+
export { ARS_VALIDATOR_MESSAGES, EmailsValidatorDirective, EqualsValidatorDirective, FileSizeValidatorDirective, GuidValidatorDirective, MIN_VALID_YEAR, MaxTermsValidatorDirective, NotEmptyValidatorDirective, NotEqualValidatorDirective, NotFutureValidatorDirective, PasswordValidatorDirective, SignalsUtils, SqlDateValidatorDirective, TimeValidatorDirective, UrlValidatorDirective, ValidIfDirective, ValidatorDirective, date, dateRange, emails, equals, fileSize, guid, maxTerms, notEmpty, notEqual, notFuture, otp, password, sqlDate, time, url, validIf };
|
|
906
1265
|
//# sourceMappingURL=arsedizioni-ars-utils-core.validators.mjs.map
|