@dhis2/ui-forms 10.16.2 → 10.16.3-alpha.1

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 (168) hide show
  1. package/package.json +12 -11
  2. package/src/CheckboxFieldFF/CheckboxFieldFF.e2e.stories.js +52 -0
  3. package/src/CheckboxFieldFF/CheckboxFieldFF.js +52 -0
  4. package/src/CheckboxFieldFF/CheckboxFieldFF.prod.stories.js +142 -0
  5. package/src/CheckboxFieldFF/features/can_toggle_a_boolean/index.js +19 -0
  6. package/src/CheckboxFieldFF/features/can_toggle_a_boolean.feature +11 -0
  7. package/src/CheckboxFieldFF/features/can_toggle_a_value/index.js +21 -0
  8. package/src/CheckboxFieldFF/features/can_toggle_a_value.feature +11 -0
  9. package/src/CheckboxFieldFF/features/common/index.js +5 -0
  10. package/src/CheckboxFieldFF/features/displays_error/index.js +18 -0
  11. package/src/CheckboxFieldFF/features/displays_error.feature +6 -0
  12. package/src/FieldGroupFF/FieldGroupFF.js +42 -0
  13. package/src/FieldGroupFF/FieldGroupFF.prod.stories.js +49 -0
  14. package/src/FileInputFieldFF/FileInputFieldFF.e2e.stories.js +272 -0
  15. package/src/FileInputFieldFF/FileInputFieldFF.js +100 -0
  16. package/src/FileInputFieldFF/FileInputFieldFF.prod.stories.js +95 -0
  17. package/src/FileInputFieldFF/features/accepts_file/index.js +40 -0
  18. package/src/FileInputFieldFF/features/accepts_file.feature +13 -0
  19. package/src/FileInputFieldFF/features/common/index.js +9 -0
  20. package/src/FileInputFieldFF/features/displays_error/index.js +18 -0
  21. package/src/FileInputFieldFF/features/displays_error.feature +8 -0
  22. package/src/InputFieldFF/InputFieldFF.e2e.stories.js +19 -0
  23. package/src/InputFieldFF/InputFieldFF.js +58 -0
  24. package/src/InputFieldFF/InputFieldFF.prod.stories.js +102 -0
  25. package/src/InputFieldFF/features/can_set_a_value/index.js +14 -0
  26. package/src/InputFieldFF/features/can_set_a_value.feature +6 -0
  27. package/src/InputFieldFF/features/displays_error/index.js +15 -0
  28. package/src/InputFieldFF/features/displays_error.feature +6 -0
  29. package/src/MultiSelectFieldFF/MultiSelectFieldFF.e2e.stories.js +27 -0
  30. package/src/MultiSelectFieldFF/MultiSelectFieldFF.js +72 -0
  31. package/src/MultiSelectFieldFF/MultiSelectFieldFF.prod.stories.js +79 -0
  32. package/src/MultiSelectFieldFF/features/can_set_a_value/index.js +38 -0
  33. package/src/MultiSelectFieldFF/features/can_set_a_value.feature +14 -0
  34. package/src/MultiSelectFieldFF/features/common/index.js +7 -0
  35. package/src/MultiSelectFieldFF/features/displays_error/index.js +10 -0
  36. package/src/MultiSelectFieldFF/features/displays_error.feature +6 -0
  37. package/src/RadioFieldFF/RadioFieldFF.e2e.stories.js +39 -0
  38. package/src/RadioFieldFF/RadioFieldFF.js +52 -0
  39. package/src/RadioFieldFF/RadioFieldFF.prod.stories.js +104 -0
  40. package/src/RadioFieldFF/features/can_set_a_value/index.js +24 -0
  41. package/src/RadioFieldFF/features/can_set_a_value.feature +7 -0
  42. package/src/RadioFieldFF/features/common/index.js +9 -0
  43. package/src/RadioFieldFF/features/displays_error/index.js +13 -0
  44. package/src/RadioFieldFF/features/displays_error.feature +6 -0
  45. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.js +172 -0
  46. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.prod.stories.js +79 -0
  47. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.test.js +82 -0
  48. package/src/SingleSelectFieldFF/SingleSelectFieldFF.e2e.stories.js +23 -0
  49. package/src/SingleSelectFieldFF/SingleSelectFieldFF.js +70 -0
  50. package/src/SingleSelectFieldFF/SingleSelectFieldFF.prod.stories.js +77 -0
  51. package/src/SingleSelectFieldFF/features/can_set_a_value/index.js +22 -0
  52. package/src/SingleSelectFieldFF/features/can_set_a_value.feature +7 -0
  53. package/src/SingleSelectFieldFF/features/common/index.js +6 -0
  54. package/src/SingleSelectFieldFF/features/displays_error/index.js +10 -0
  55. package/src/SingleSelectFieldFF/features/displays_error.feature +6 -0
  56. package/src/SwitchFieldFF/SwitchFieldFF.e2e.stories.js +52 -0
  57. package/src/SwitchFieldFF/SwitchFieldFF.js +52 -0
  58. package/src/SwitchFieldFF/SwitchFieldFF.prod.stories.js +148 -0
  59. package/src/SwitchFieldFF/features/can_toggle_a_boolean/index.js +19 -0
  60. package/src/SwitchFieldFF/features/can_toggle_a_boolean.feature +11 -0
  61. package/src/SwitchFieldFF/features/can_toggle_a_value/index.js +21 -0
  62. package/src/SwitchFieldFF/features/can_toggle_a_value.feature +11 -0
  63. package/src/SwitchFieldFF/features/common/index.js +5 -0
  64. package/src/SwitchFieldFF/features/displays_error/index.js +18 -0
  65. package/src/SwitchFieldFF/features/displays_error.feature +6 -0
  66. package/src/TextAreaFieldFF/TextAreaFieldFF.e2e.stories.js +23 -0
  67. package/src/TextAreaFieldFF/TextAreaFieldFF.js +57 -0
  68. package/src/TextAreaFieldFF/TextAreaFieldFF.prod.stories.js +111 -0
  69. package/src/TextAreaFieldFF/features/can_set_a_value/index.js +14 -0
  70. package/src/TextAreaFieldFF/features/can_set_a_value.feature +6 -0
  71. package/src/TextAreaFieldFF/features/displays_error/index.js +15 -0
  72. package/src/TextAreaFieldFF/features/displays_error.feature +6 -0
  73. package/src/__tests__/__snapshots__/index.test.js.snap +65 -0
  74. package/src/__tests__/index.test.js +37 -0
  75. package/src/formDecorator.js +80 -0
  76. package/src/index.js +28 -0
  77. package/src/locales/ar/translations.json +30 -0
  78. package/src/locales/ar_IQ/translations.json +30 -0
  79. package/src/locales/ckb/translations.json +30 -0
  80. package/src/locales/cs/translations.json +30 -0
  81. package/src/locales/da/translations.json +30 -0
  82. package/src/locales/en/translations.json +30 -0
  83. package/src/locales/es/translations.json +30 -0
  84. package/src/locales/es_419/translations.json +30 -0
  85. package/src/locales/fr/translations.json +30 -0
  86. package/src/locales/hi_IN/translations.json +30 -0
  87. package/src/locales/id/translations.json +30 -0
  88. package/src/locales/index.js +84 -0
  89. package/src/locales/km/translations.json +30 -0
  90. package/src/locales/ko_KR/translations.json +30 -0
  91. package/src/locales/lo/translations.json +30 -0
  92. package/src/locales/my/translations.json +30 -0
  93. package/src/locales/nb/translations.json +30 -0
  94. package/src/locales/nl/translations.json +30 -0
  95. package/src/locales/prs/translations.json +30 -0
  96. package/src/locales/ps/translations.json +30 -0
  97. package/src/locales/pt/translations.json +30 -0
  98. package/src/locales/pt_BR/translations.json +30 -0
  99. package/src/locales/ro/translations.json +30 -0
  100. package/src/locales/ru/translations.json +30 -0
  101. package/src/locales/si/translations.json +30 -0
  102. package/src/locales/sv/translations.json +30 -0
  103. package/src/locales/tet/translations.json +30 -0
  104. package/src/locales/tg/translations.json +30 -0
  105. package/src/locales/uk/translations.json +30 -0
  106. package/src/locales/ur/translations.json +30 -0
  107. package/src/locales/uz_Latn/translations.json +30 -0
  108. package/src/locales/uz_UZ_Cyrl/translations.json +30 -0
  109. package/src/locales/uz_UZ_Latn/translations.json +30 -0
  110. package/src/locales/vi/translations.json +30 -0
  111. package/src/locales/zh/translations.json +30 -0
  112. package/src/locales/zh_CN/translations.json +30 -0
  113. package/src/shared/helpers/createBlurHandler.js +9 -0
  114. package/src/shared/helpers/createChangeHandler.js +21 -0
  115. package/src/shared/helpers/createFocusHandler.js +9 -0
  116. package/src/shared/helpers/createSelectChangeHandler.js +6 -0
  117. package/src/shared/helpers/createToggleChangeHandler.js +9 -0
  118. package/src/shared/helpers/getValidationText.js +21 -0
  119. package/src/shared/helpers/hasError.js +3 -0
  120. package/src/shared/helpers/isLoading.js +4 -0
  121. package/src/shared/helpers/isValid.js +4 -0
  122. package/src/shared/helpers.js +9 -0
  123. package/src/shared/propTypes.js +48 -0
  124. package/src/transformers/arrayWithIdObjects.js +8 -0
  125. package/src/transformers/index.js +1 -0
  126. package/src/validators/__tests__/alphaNumeric.test.js +29 -0
  127. package/src/validators/__tests__/boolean.test.js +23 -0
  128. package/src/validators/__tests__/composeValidators.test.js +23 -0
  129. package/src/validators/__tests__/createCharacterLengthRange.test.js +59 -0
  130. package/src/validators/__tests__/createEqualTo.test.js +43 -0
  131. package/src/validators/__tests__/createMaxCharacterLength.test.js +24 -0
  132. package/src/validators/__tests__/createMaxNumber.test.js +21 -0
  133. package/src/validators/__tests__/createMinCharacterLength.test.js +24 -0
  134. package/src/validators/__tests__/createMinNumber.test.js +21 -0
  135. package/src/validators/__tests__/createNumberRange.test.js +68 -0
  136. package/src/validators/__tests__/createPattern.test.js +40 -0
  137. package/src/validators/__tests__/dhis2Password.test.js +51 -0
  138. package/src/validators/__tests__/dhis2Username.test.js +75 -0
  139. package/src/validators/__tests__/email.test.js +83 -0
  140. package/src/validators/__tests__/hasValue.test.js +21 -0
  141. package/src/validators/__tests__/integer.test.js +48 -0
  142. package/src/validators/__tests__/internationalPhoneNumber.test.js +49 -0
  143. package/src/validators/__tests__/number.test.js +39 -0
  144. package/src/validators/__tests__/string.test.js +29 -0
  145. package/src/validators/__tests__/url.test.js +106 -0
  146. package/src/validators/alphaNumeric.js +15 -0
  147. package/src/validators/boolean.js +11 -0
  148. package/src/validators/composeValidators.js +8 -0
  149. package/src/validators/createCharacterLengthRange.js +27 -0
  150. package/src/validators/createEqualTo.js +16 -0
  151. package/src/validators/createMaxCharacterLength.js +13 -0
  152. package/src/validators/createMaxNumber.js +13 -0
  153. package/src/validators/createMinCharacterLength.js +13 -0
  154. package/src/validators/createMinNumber.js +13 -0
  155. package/src/validators/createNumberRange.js +28 -0
  156. package/src/validators/createPattern.js +22 -0
  157. package/src/validators/dhis2Password.js +81 -0
  158. package/src/validators/dhis2Username.js +16 -0
  159. package/src/validators/email.js +38 -0
  160. package/src/validators/hasValue.js +8 -0
  161. package/src/validators/helpers/index.js +23 -0
  162. package/src/validators/index.js +20 -0
  163. package/src/validators/integer.js +20 -0
  164. package/src/validators/internationalPhoneNumber.js +56 -0
  165. package/src/validators/number.js +9 -0
  166. package/src/validators/string.js +9 -0
  167. package/src/validators/test-helpers/index.js +21 -0
  168. package/src/validators/url.js +15 -0
@@ -0,0 +1,81 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString } from './helpers/index.js'
3
+
4
+ const LOWER_CASE_PATTERN = /^(?=.*[a-z]).+$/
5
+ const UPPER_CASE_PATTERN = /^(?=.*[A-Z]).+$/
6
+ const DIGIT_PATTERN = /^(?=.*[0-9]).+$/
7
+ // Using this regex to match all non-alphanumeric characters to match server-side implementation
8
+ // https://github.com/dhis2/dhis2-core/blob/master/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/SpecialCharacterValidationRule.java#L39
9
+ const SPECIAL_CHARACTER_PATTERN = /[^a-zA-Z0-9]/
10
+
11
+ const notString = i18n.t('Password should be a string')
12
+ const tooShort = i18n.t('Password should be at least 8 characters long')
13
+ const tooLong = i18n.t('Password should be no longer than 34 characters')
14
+ const noLowerCase = i18n.t(
15
+ 'Password should contain at least one lowercase letter'
16
+ )
17
+ const noUpperCase = i18n.t(
18
+ 'Password should contain at least one UPPERCASE letter'
19
+ )
20
+ const noNumber = i18n.t('Password should contain at least one number')
21
+ const noSpecialCharacter = i18n.t(
22
+ 'Password should have at least one special character'
23
+ )
24
+
25
+ /**
26
+ * Tests if a given password is compliant with the password restrictions.
27
+ * This function checks all restrictions below, but returns when the first violation was found:
28
+ * - At least 8 characters
29
+ * - No more than 34 characters
30
+ * - Contains at least 1 lowercase character
31
+ * - Contains at least 1 UPPERCASE character
32
+ * - Contains at least 1 number
33
+ * - Contains at least 1 special character
34
+ */
35
+ const dhis2Password = (value) => {
36
+ if (isEmpty(value)) {
37
+ return undefined
38
+ }
39
+
40
+ if (!isString(value)) {
41
+ return notString
42
+ }
43
+
44
+ if (value.length < 8) {
45
+ return tooShort
46
+ }
47
+
48
+ if (value.length > 35) {
49
+ return tooLong
50
+ }
51
+
52
+ if (!LOWER_CASE_PATTERN.test(value)) {
53
+ return noLowerCase
54
+ }
55
+
56
+ if (!UPPER_CASE_PATTERN.test(value)) {
57
+ return noUpperCase
58
+ }
59
+
60
+ if (!DIGIT_PATTERN.test(value)) {
61
+ return noNumber
62
+ }
63
+
64
+ if (!SPECIAL_CHARACTER_PATTERN.test(value)) {
65
+ return noSpecialCharacter
66
+ }
67
+
68
+ return undefined
69
+ }
70
+
71
+ const errorMessages = {
72
+ notString,
73
+ tooShort,
74
+ tooLong,
75
+ noLowerCase,
76
+ noUpperCase,
77
+ noNumber,
78
+ noSpecialCharacter,
79
+ }
80
+
81
+ export { dhis2Password, errorMessages }
@@ -0,0 +1,16 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString } from './helpers/index.js'
3
+
4
+ const USERNAME_PATTERN =
5
+ /^(?=.{4,255}$)(?![_\-.@])(?!.*[_\-.@]{2})[a-zA-Z0-9._\-@]+(?<![_\-.@])$/
6
+
7
+ const invalidUsernameMessage = i18n.t(
8
+ 'Please provide a username between 4 and 255 characters long and possibly separated by . _ - or @'
9
+ )
10
+
11
+ const dhis2Username = (value) =>
12
+ isEmpty(value) || (isString(value) && USERNAME_PATTERN.test(value))
13
+ ? undefined
14
+ : invalidUsernameMessage
15
+
16
+ export { dhis2Username, invalidUsernameMessage }
@@ -0,0 +1,38 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString } from './helpers/index.js'
3
+
4
+ /*
5
+ * Email validation is complicated business. There is no perfect regex,
6
+ * instead we have to make a trade-off between complexity, correctness,
7
+ * and the risk of producing false negatives. This article
8
+ * https://www.regular-expressions.info/email.html offers a good overview.
9
+ * It recommends to use a very simple regex when having to validate many
10
+ * records, but for validating an individual email address a more complex
11
+ * regex may be used.
12
+ *
13
+ * The pattern below is taken from the "The Official Standard: RFC 5322"
14
+ * section of the article and is described as:
15
+ * "[..] a more practical implementation of RFC 5322 [..] that will still
16
+ * match 99.99% of all email addresses in actual use today"
17
+ *
18
+ * const EMAIL_ADDRESS_PATTERN = /[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i
19
+ *
20
+ * However, this regex produces a few false negatives and quite a lot
21
+ * of false positives.
22
+ *
23
+ * Another regex, found in this stackoverflow answer below resulted in a better
24
+ * overall picture in terms of false negatives and positives, so I settled on that one:
25
+ * https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript/46181#46181
26
+ */
27
+
28
+ const EMAIL_ADDRESS_PATTERN =
29
+ /^(([^<>()[\]\\.,;:\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,}))$/i
30
+
31
+ const invalidEmailMessage = i18n.t('Please provide a valid email address')
32
+
33
+ const email = (value) =>
34
+ isEmpty(value) || (isString(value) && EMAIL_ADDRESS_PATTERN.test(value))
35
+ ? undefined
36
+ : invalidEmailMessage
37
+
38
+ export { email, invalidEmailMessage }
@@ -0,0 +1,8 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty } from './helpers/index.js'
3
+
4
+ const hasValueMessage = i18n.t('Please provide a value')
5
+
6
+ const hasValue = (value) => (isEmpty(value) ? hasValueMessage : undefined)
7
+
8
+ export { hasValue, hasValueMessage }
@@ -0,0 +1,23 @@
1
+ export const isEmpty = (value) =>
2
+ typeof value === 'undefined' || value === null || value === ''
3
+
4
+ export const isString = (value) => typeof value === 'string'
5
+
6
+ export const isNumber = (value) => typeof value === 'number'
7
+
8
+ export const isNumeric = (value) =>
9
+ (isString(value) || isNumber(value)) && !isNaN(value)
10
+
11
+ export const isInRange = (lowerBound, upperBound, value) =>
12
+ value >= lowerBound && value <= upperBound
13
+
14
+ export const toNumber = (value) => Number(value)
15
+
16
+ export const requiredArgumentErrorMessage =
17
+ 'Incorrect arguments provided when creating validator'
18
+
19
+ export const requireArgument = (value, type) => {
20
+ if (isEmpty(value) || typeof value !== type) {
21
+ throw new Error(requiredArgumentErrorMessage)
22
+ }
23
+ }
@@ -0,0 +1,20 @@
1
+ export { alphaNumeric } from './alphaNumeric.js'
2
+ export { boolean } from './boolean.js'
3
+ export { composeValidators } from './composeValidators.js'
4
+ export { createCharacterLengthRange } from './createCharacterLengthRange.js'
5
+ export { createEqualTo } from './createEqualTo.js'
6
+ export { createMaxCharacterLength } from './createMaxCharacterLength.js'
7
+ export { createMaxNumber } from './createMaxNumber.js'
8
+ export { createMinCharacterLength } from './createMinCharacterLength.js'
9
+ export { createMinNumber } from './createMinNumber.js'
10
+ export { createNumberRange } from './createNumberRange.js'
11
+ export { createPattern } from './createPattern.js'
12
+ export { dhis2Password } from './dhis2Password.js'
13
+ export { dhis2Username } from './dhis2Username.js'
14
+ export { email } from './email.js'
15
+ export { hasValue } from './hasValue.js'
16
+ export { integer } from './integer.js'
17
+ export { internationalPhoneNumber } from './internationalPhoneNumber.js'
18
+ export { number } from './number.js'
19
+ export { string } from './string.js'
20
+ export { url } from './url.js'
@@ -0,0 +1,20 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isNumeric, toNumber } from './helpers/index.js'
3
+
4
+ const invalidIntegerMessage = i18n.t(
5
+ 'Please provide a round number without decimals'
6
+ )
7
+
8
+ // Regex accepts only digits (no decimals even if it is trailing like 4.0)
9
+ // it also rejects a leading 0 (i.e 04) as this is rejected by backend
10
+ const INTEGER_PATTERN = /^(-?[1-9]\d*|0)$/
11
+
12
+ const integer = (value) =>
13
+ isEmpty(value) ||
14
+ (INTEGER_PATTERN.test(value) &&
15
+ isNumeric(value) &&
16
+ Number.isSafeInteger(toNumber(value)))
17
+ ? undefined
18
+ : invalidIntegerMessage
19
+
20
+ export { integer, invalidIntegerMessage }
@@ -0,0 +1,56 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString, isNumeric } from './helpers/index.js'
3
+
4
+ /*
5
+ * There were some problems with the server side implementation
6
+ * of how international phone numbers are validated, and the
7
+ * server side implementation will likely be removed, see:
8
+ * https://jira.dhis2.org/browse/DHIS2-8040
9
+ *
10
+ * So, rather than aligning with the server-side implementation
11
+ * this validator implements the E.164 numbering plan, see:
12
+ * https://www.cm.com/blog/how-to-format-international-telephone-numbers/
13
+ *
14
+ * SPECS
15
+ * Here's how the E.164 numbering plan works:
16
+ * - A telephone number can have a maximum of 15 digits
17
+ * - The first part of the telephone number is the country code (one to three digits)
18
+ * - The second part is the national destination code (NDC)
19
+ * - The last part is the subscriber number (SN)
20
+ * - The NDC and SN together are collectively called the national (significant) number
21
+ *
22
+ * IMPLEMENTATION ADVICE
23
+ * Two important things to note: First of all, in the international E.164 notation a
24
+ * leading ‘0’ is removed. The UK mobile phone number ‘07911 123456’ in international
25
+ * format is ‘+44 7911 123456’, so without the first zero. Secondly in the E.164 notation
26
+ * all spaces, dashes [‘-‘] and parentheses [ ‘(‘ and ‘)’] are removed, besides the
27
+ * leading ‘+’ all characters should be numeric.
28
+ */
29
+
30
+ const invalidInternationalPhoneNumberMessage = i18n.t(
31
+ 'Please provide a valid international phone number.'
32
+ )
33
+
34
+ const internationalPhoneNumber = (value) => {
35
+ // allow empty values
36
+ if (isEmpty(value)) {
37
+ return undefined
38
+ }
39
+
40
+ // value must be a string
41
+ if (!isString(value)) {
42
+ return invalidInternationalPhoneNumberMessage
43
+ }
44
+
45
+ const cleanedValue = value
46
+ // strip all hyphens, dots, spaces
47
+ .replace(/[-. )(]/g, '')
48
+ // trim leading zeroes and plus signs
49
+ .replace(/^[0+]+/, '')
50
+
51
+ return isNumeric(cleanedValue) && cleanedValue.length <= 15
52
+ ? undefined
53
+ : invalidInternationalPhoneNumberMessage
54
+ }
55
+
56
+ export { internationalPhoneNumber, invalidInternationalPhoneNumberMessage }
@@ -0,0 +1,9 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isNumeric } from './helpers/index.js'
3
+
4
+ const invalidNumberMessage = i18n.t('Please provide a number')
5
+
6
+ const number = (value) =>
7
+ isEmpty(value) || isNumeric(value) ? undefined : invalidNumberMessage
8
+
9
+ export { number, invalidNumberMessage }
@@ -0,0 +1,9 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString } from './helpers/index.js'
3
+
4
+ const invalidStringMessage = i18n.t('Please provide a string')
5
+
6
+ const string = (value) =>
7
+ isEmpty(value) || isString(value) ? undefined : invalidStringMessage
8
+
9
+ export { string, invalidStringMessage }
@@ -0,0 +1,21 @@
1
+ const testValidatorValues = (validator, returnValue, values) => {
2
+ const returnValueStr =
3
+ returnValue === undefined ? 'undefined' : 'an error string'
4
+
5
+ for (const value of values) {
6
+ const type = typeof value
7
+ const valueStr = type === 'object' ? JSON.stringify(value) : value
8
+
9
+ it(`should return ${returnValueStr} for value \`${valueStr}\` of type ${type}`, () => {
10
+ expect(validator(value)).toBe(returnValue)
11
+ })
12
+ }
13
+ }
14
+
15
+ const allowsEmptyValues = (validator) => {
16
+ describe('allows empty values', () => {
17
+ testValidatorValues(validator, undefined, ['', null, undefined])
18
+ })
19
+ }
20
+
21
+ export { testValidatorValues, allowsEmptyValues }
@@ -0,0 +1,15 @@
1
+ import i18n from '../locales/index.js'
2
+ import { isEmpty, isString } from './helpers/index.js'
3
+
4
+ // Source: https://gist.github.com/dperini/729294
5
+ const URL_PATTERN =
6
+ /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i
7
+
8
+ const invalidUrlMessage = i18n.t('Please provide a valid url')
9
+
10
+ const url = (value) =>
11
+ isEmpty(value) || (isString(value) && URL_PATTERN.test(value))
12
+ ? undefined
13
+ : invalidUrlMessage
14
+
15
+ export { url, invalidUrlMessage }