@dwp/govuk-casa 9.0.0 → 9.1.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.
Files changed (199) hide show
  1. package/README.md +9 -9
  2. package/dist/assets/css/casa.css +1 -1
  3. package/dist/assets/css/casa.css.map +1 -1
  4. package/dist/casa.d.ts +122 -95
  5. package/dist/casa.js +119 -86
  6. package/dist/casa.js.map +1 -1
  7. package/dist/lib/CasaTemplateLoader.d.ts +4 -4
  8. package/dist/lib/CasaTemplateLoader.js +16 -16
  9. package/dist/lib/CasaTemplateLoader.js.map +1 -1
  10. package/dist/lib/JourneyContext.d.ts +38 -40
  11. package/dist/lib/JourneyContext.js +81 -75
  12. package/dist/lib/JourneyContext.js.map +1 -1
  13. package/dist/lib/MutableRouter.d.ts +40 -41
  14. package/dist/lib/MutableRouter.js +64 -71
  15. package/dist/lib/MutableRouter.js.map +1 -1
  16. package/dist/lib/Plan.d.ts +29 -26
  17. package/dist/lib/Plan.js +85 -71
  18. package/dist/lib/Plan.js.map +1 -1
  19. package/dist/lib/ValidationError.d.ts +16 -15
  20. package/dist/lib/ValidationError.js +21 -20
  21. package/dist/lib/ValidationError.js.map +1 -1
  22. package/dist/lib/ValidatorFactory.d.ts +15 -13
  23. package/dist/lib/ValidatorFactory.js +14 -12
  24. package/dist/lib/ValidatorFactory.js.map +1 -1
  25. package/dist/lib/configuration-ingestor.d.ts +37 -40
  26. package/dist/lib/configuration-ingestor.js +93 -93
  27. package/dist/lib/configuration-ingestor.js.map +1 -1
  28. package/dist/lib/configure.d.ts +6 -6
  29. package/dist/lib/configure.js +14 -12
  30. package/dist/lib/configure.js.map +1 -1
  31. package/dist/lib/constants.d.ts +1 -3
  32. package/dist/lib/constants.js +9 -11
  33. package/dist/lib/constants.js.map +1 -1
  34. package/dist/lib/context-id-generators.d.ts +3 -5
  35. package/dist/lib/context-id-generators.js +7 -6
  36. package/dist/lib/context-id-generators.js.map +1 -1
  37. package/dist/lib/end-session.d.ts +4 -4
  38. package/dist/lib/end-session.js +5 -5
  39. package/dist/lib/field.d.ts +20 -18
  40. package/dist/lib/field.js +35 -48
  41. package/dist/lib/field.js.map +1 -1
  42. package/dist/lib/index.d.ts +13 -13
  43. package/dist/lib/logger.d.ts +7 -6
  44. package/dist/lib/logger.js +7 -7
  45. package/dist/lib/logger.js.map +1 -1
  46. package/dist/lib/mount.d.ts +5 -5
  47. package/dist/lib/mount.js +11 -10
  48. package/dist/lib/mount.js.map +1 -1
  49. package/dist/lib/nunjucks-filters.d.ts +10 -12
  50. package/dist/lib/nunjucks-filters.js +35 -35
  51. package/dist/lib/nunjucks-filters.js.map +1 -1
  52. package/dist/lib/nunjucks.d.ts +7 -5
  53. package/dist/lib/nunjucks.js +10 -8
  54. package/dist/lib/nunjucks.js.map +1 -1
  55. package/dist/lib/utils.d.ts +19 -19
  56. package/dist/lib/utils.js +62 -55
  57. package/dist/lib/utils.js.map +1 -1
  58. package/dist/lib/validators/dateObject.d.ts +29 -22
  59. package/dist/lib/validators/dateObject.js +58 -49
  60. package/dist/lib/validators/dateObject.js.map +1 -1
  61. package/dist/lib/validators/email.d.ts +4 -4
  62. package/dist/lib/validators/email.js +4 -4
  63. package/dist/lib/validators/inArray.d.ts +4 -4
  64. package/dist/lib/validators/inArray.js +7 -8
  65. package/dist/lib/validators/inArray.js.map +1 -1
  66. package/dist/lib/validators/index.d.ts +10 -10
  67. package/dist/lib/validators/index.js +1 -3
  68. package/dist/lib/validators/index.js.map +1 -1
  69. package/dist/lib/validators/nino.d.ts +9 -8
  70. package/dist/lib/validators/nino.js +14 -10
  71. package/dist/lib/validators/nino.js.map +1 -1
  72. package/dist/lib/validators/postalAddressObject.d.ts +37 -24
  73. package/dist/lib/validators/postalAddressObject.js +65 -46
  74. package/dist/lib/validators/postalAddressObject.js.map +1 -1
  75. package/dist/lib/validators/range.d.ts +12 -8
  76. package/dist/lib/validators/range.js +11 -9
  77. package/dist/lib/validators/range.js.map +1 -1
  78. package/dist/lib/validators/regex.d.ts +4 -4
  79. package/dist/lib/validators/regex.js +5 -5
  80. package/dist/lib/validators/required.d.ts +6 -6
  81. package/dist/lib/validators/required.js +9 -11
  82. package/dist/lib/validators/required.js.map +1 -1
  83. package/dist/lib/validators/strlen.d.ts +12 -8
  84. package/dist/lib/validators/strlen.js +13 -11
  85. package/dist/lib/validators/strlen.js.map +1 -1
  86. package/dist/lib/validators/wordCount.d.ts +12 -8
  87. package/dist/lib/validators/wordCount.js +15 -11
  88. package/dist/lib/validators/wordCount.js.map +1 -1
  89. package/dist/lib/waypoint-url.d.ts +16 -13
  90. package/dist/lib/waypoint-url.js +39 -36
  91. package/dist/lib/waypoint-url.js.map +1 -1
  92. package/dist/middleware/body-parser.d.ts +1 -1
  93. package/dist/middleware/body-parser.js +6 -6
  94. package/dist/middleware/body-parser.js.map +1 -1
  95. package/dist/middleware/data.d.ts +1 -1
  96. package/dist/middleware/data.js +8 -7
  97. package/dist/middleware/data.js.map +1 -1
  98. package/dist/middleware/gather-fields.d.ts +2 -2
  99. package/dist/middleware/gather-fields.js +6 -4
  100. package/dist/middleware/gather-fields.js.map +1 -1
  101. package/dist/middleware/i18n.js +13 -15
  102. package/dist/middleware/i18n.js.map +1 -1
  103. package/dist/middleware/post.js +30 -18
  104. package/dist/middleware/post.js.map +1 -1
  105. package/dist/middleware/pre.d.ts +2 -2
  106. package/dist/middleware/pre.js +46 -27
  107. package/dist/middleware/pre.js.map +1 -1
  108. package/dist/middleware/progress-journey.d.ts +1 -1
  109. package/dist/middleware/progress-journey.js +5 -5
  110. package/dist/middleware/progress-journey.js.map +1 -1
  111. package/dist/middleware/sanitise-fields.d.ts +1 -1
  112. package/dist/middleware/sanitise-fields.js +13 -11
  113. package/dist/middleware/sanitise-fields.js.map +1 -1
  114. package/dist/middleware/serve-first-waypoint.d.ts +3 -3
  115. package/dist/middleware/serve-first-waypoint.js +8 -6
  116. package/dist/middleware/serve-first-waypoint.js.map +1 -1
  117. package/dist/middleware/session.js +14 -11
  118. package/dist/middleware/session.js.map +1 -1
  119. package/dist/middleware/skip-waypoint.d.ts +1 -1
  120. package/dist/middleware/skip-waypoint.js +3 -3
  121. package/dist/middleware/skip-waypoint.js.map +1 -1
  122. package/dist/middleware/steer-journey.d.ts +1 -1
  123. package/dist/middleware/steer-journey.js +16 -14
  124. package/dist/middleware/steer-journey.js.map +1 -1
  125. package/dist/middleware/strip-proxy-path.d.ts +1 -1
  126. package/dist/middleware/strip-proxy-path.js +3 -3
  127. package/dist/middleware/strip-proxy-path.js.map +1 -1
  128. package/dist/middleware/validate-fields.d.ts +1 -1
  129. package/dist/middleware/validate-fields.js +2 -5
  130. package/dist/middleware/validate-fields.js.map +1 -1
  131. package/dist/routes/ancillary.d.ts +3 -3
  132. package/dist/routes/ancillary.js +4 -4
  133. package/dist/routes/ancillary.js.map +1 -1
  134. package/dist/routes/journey.d.ts +2 -2
  135. package/dist/routes/journey.js +91 -39
  136. package/dist/routes/journey.js.map +1 -1
  137. package/dist/routes/static.d.ts +7 -5
  138. package/dist/routes/static.js +20 -19
  139. package/dist/routes/static.js.map +1 -1
  140. package/package.json +19 -18
  141. package/src/casa.js +133 -100
  142. package/src/lib/CasaTemplateLoader.js +24 -19
  143. package/src/lib/JourneyContext.js +138 -107
  144. package/src/lib/MutableRouter.js +72 -74
  145. package/src/lib/Plan.js +145 -97
  146. package/src/lib/ValidationError.js +25 -21
  147. package/src/lib/ValidatorFactory.js +17 -13
  148. package/src/lib/configuration-ingestor.js +147 -110
  149. package/src/lib/configure.js +34 -32
  150. package/src/lib/constants.js +9 -11
  151. package/src/lib/context-id-generators.js +40 -43
  152. package/src/lib/end-session.js +6 -6
  153. package/src/lib/field.js +69 -58
  154. package/src/lib/index.js +12 -12
  155. package/src/lib/logger.js +9 -9
  156. package/src/lib/mount.js +70 -74
  157. package/src/lib/nunjucks-filters.js +56 -59
  158. package/src/lib/nunjucks.js +23 -18
  159. package/src/lib/utils.js +78 -57
  160. package/src/lib/validators/dateObject.js +71 -60
  161. package/src/lib/validators/email.js +8 -8
  162. package/src/lib/validators/inArray.js +10 -11
  163. package/src/lib/validators/index.js +12 -14
  164. package/src/lib/validators/nino.js +29 -15
  165. package/src/lib/validators/postalAddressObject.js +87 -63
  166. package/src/lib/validators/range.js +14 -12
  167. package/src/lib/validators/regex.js +8 -8
  168. package/src/lib/validators/required.js +16 -16
  169. package/src/lib/validators/strlen.js +16 -14
  170. package/src/lib/validators/wordCount.js +22 -14
  171. package/src/lib/waypoint-url.js +64 -46
  172. package/src/middleware/body-parser.js +10 -10
  173. package/src/middleware/csrf.js +1 -1
  174. package/src/middleware/data.js +28 -24
  175. package/src/middleware/gather-fields.js +10 -9
  176. package/src/middleware/i18n.js +35 -37
  177. package/src/middleware/post.js +41 -21
  178. package/src/middleware/pre.js +62 -41
  179. package/src/middleware/progress-journey.js +32 -18
  180. package/src/middleware/sanitise-fields.js +43 -20
  181. package/src/middleware/serve-first-waypoint.js +14 -12
  182. package/src/middleware/session.js +74 -61
  183. package/src/middleware/skip-waypoint.js +7 -9
  184. package/src/middleware/steer-journey.js +40 -28
  185. package/src/middleware/strip-proxy-path.js +8 -7
  186. package/src/middleware/validate-fields.js +5 -12
  187. package/src/routes/ancillary.js +5 -7
  188. package/src/routes/journey.js +159 -85
  189. package/src/routes/static.js +62 -29
  190. package/views/casa/components/character-count/README.md +2 -2
  191. package/views/casa/components/checkboxes/README.md +6 -6
  192. package/views/casa/components/date-input/README.md +7 -7
  193. package/views/casa/components/input/README.md +2 -2
  194. package/views/casa/components/journey-form/README.md +33 -14
  195. package/views/casa/components/postal-address-object/README.md +4 -4
  196. package/views/casa/components/radios/README.md +6 -6
  197. package/views/casa/components/select/README.md +6 -6
  198. package/views/casa/components/textarea/README.md +2 -2
  199. package/views/casa/layouts/main.njk +2 -1
package/src/lib/utils.js CHANGED
@@ -1,24 +1,24 @@
1
1
  /**
2
+ * @typedef {import("../casa").GlobalHook | import("../casa").PageHook} Hook
2
3
  * @access private
3
- * @typedef {import('../casa').GlobalHook | import('../casa').PageHook} Hook
4
4
  */
5
5
 
6
6
  /**
7
7
  * Determine if value is empty. Recurse over objects.
8
8
  *
9
- * @access private
10
- * @param {any} val Value to check
9
+ * @param {any} val Value to check
11
10
  * @returns {boolean} True if the object is empty
11
+ * @access private
12
12
  */
13
13
  export function isEmpty(val) {
14
14
  if (
15
- val === null
16
- || typeof val === 'undefined'
17
- || (typeof val === 'string' && val === '')
15
+ val === null ||
16
+ typeof val === "undefined" ||
17
+ (typeof val === "string" && val === "")
18
18
  ) {
19
19
  return true;
20
20
  }
21
- if (Array.isArray(val) || typeof val === 'object') {
21
+ if (Array.isArray(val) || typeof val === "object") {
22
22
  // ESLint disabled as `k` is an "own property" (thanks to `Object.keys()`)
23
23
  /* eslint-disable-next-line security/detect-object-injection */
24
24
  return Object.keys(val).filter((k) => !isEmpty(val[k])).length === 0;
@@ -29,41 +29,50 @@ export function isEmpty(val) {
29
29
  /**
30
30
  * Test is a value can be stringified (numbers or strings)
31
31
  *
32
- * @access private
33
32
  * @param {any} value Item to test
34
33
  * @returns {boolean} Whether the value is stringable or not
34
+ * @access private
35
35
  */
36
36
  export function isStringable(value) {
37
- return typeof value === 'string' || typeof value === 'number';
37
+ return typeof value === "string" || typeof value === "number";
38
38
  }
39
39
 
40
40
  /**
41
41
  * Extract the middleware functions that are relevant for the given hook and
42
42
  * path.
43
43
  *
44
- * @access private
45
44
  * @param {string} hookName Hook name (including scope prefix)
46
45
  * @param {string} path URL path to match (relative to mountUrl)
47
46
  * @param {Hook[]} hooks Hooks to be applied at the page level
48
47
  * @returns {Function[]} An array of middleware that should be applied
48
+ * @access private
49
49
  */
50
50
  export function resolveMiddlewareHooks(hookName, path, hooks = []) {
51
51
  /* eslint-disable-next-line max-len */
52
- const pathMatch = (h) => h.path === undefined || (h.path instanceof RegExp && h.path.test(path)) || h.path === path;
53
- return hooks.filter((h) => h.hook === hookName).filter(pathMatch).map((h) => h.middleware);
52
+ const pathMatch = (h) =>
53
+ h.path === undefined ||
54
+ (h.path instanceof RegExp && h.path.test(path)) ||
55
+ h.path === path;
56
+ return hooks
57
+ .filter((h) => h.hook === hookName)
58
+ .filter(pathMatch)
59
+ .map((h) => h.middleware);
54
60
  }
55
61
 
56
62
  /**
57
63
  * Coerce an input to a string.
58
64
  *
59
- * @access private
60
65
  * @param {any} input Input to be stringified
61
66
  * @param {string} fallback Fallback to use if input can't be stringified
62
67
  * @returns {string} The stringified input
68
+ * @access private
63
69
  */
64
70
  export function stringifyInput(input, fallback) {
65
71
  // Not using param defaults here as the fallback may be explicitly "undefined"
66
- const fb = arguments.length === 2 && (isStringable(fallback) || fallback === undefined) ? fallback : '';
72
+ const fb =
73
+ arguments.length === 2 && (isStringable(fallback) || fallback === undefined)
74
+ ? fallback
75
+ : "";
67
76
  return isStringable(input) ? String(input) : fb;
68
77
  }
69
78
 
@@ -71,7 +80,7 @@ export function stringifyInput(input, fallback) {
71
80
  * Coerce an input to an integer.
72
81
  *
73
82
  * @param {any} input Input to be coerced.
74
- * @returns {number|undefined} The number as an integer or `undefined`.
83
+ * @returns {number | undefined} The number as an integer or `undefined`.
75
84
  */
76
85
  export function coerceInputToInteger(input) {
77
86
  return Number.isNaN(Number(input)) ? undefined : Math.floor(Number(input));
@@ -80,34 +89,34 @@ export function coerceInputToInteger(input) {
80
89
  /**
81
90
  * Strip whitespace from a string.
82
91
  *
83
- * @access private
84
- * @param {string} value value to be stripped of whitespace
85
- * @param {object} options overrides for the default whitespace replacements
86
- * @returns {string} value stripped of white space
92
+ * @param {string} value Value to be stripped of whitespace
93
+ * @param {object} options Overrides for the default whitespace replacements
94
+ * @returns {string} Value stripped of white space
87
95
  * @throws {TypeError}
96
+ * @access private
88
97
  */
89
98
  export function stripWhitespace(value, options) {
90
99
  const opts = {
91
- leading: '',
92
- trailing: '',
93
- nested: ' ',
100
+ leading: "",
101
+ trailing: "",
102
+ nested: " ",
94
103
  ...options,
95
104
  };
96
105
 
97
- if (typeof value !== 'string') {
98
- throw new TypeError('value must be a string');
106
+ if (typeof value !== "string") {
107
+ throw new TypeError("value must be a string");
99
108
  }
100
109
 
101
- if (typeof opts.leading !== 'string') {
102
- throw new TypeError('leading must be a string');
110
+ if (typeof opts.leading !== "string") {
111
+ throw new TypeError("leading must be a string");
103
112
  }
104
113
 
105
- if (typeof opts.trailing !== 'string') {
106
- throw new TypeError('trailing must be a string');
114
+ if (typeof opts.trailing !== "string") {
115
+ throw new TypeError("trailing must be a string");
107
116
  }
108
117
 
109
- if (typeof opts.nested !== 'string') {
110
- throw new TypeError('nested must be a string');
118
+ if (typeof opts.nested !== "string") {
119
+ throw new TypeError("nested must be a string");
111
120
  }
112
121
 
113
122
  return value
@@ -121,14 +130,18 @@ export function stripWhitespace(value, options) {
121
130
  /**
122
131
  * Checks if the given string can be used as an object key.
123
132
  *
124
- * @access private
125
133
  * @param {string} key Proposed Object key
126
134
  * @returns {string} Same key if it's valid
127
- * @throws {Error} if proposed key is an invalid keyword
135
+ * @throws {Error} If proposed key is an invalid keyword
136
+ * @access private
128
137
  */
129
138
  export function notProto(key) {
130
- if (['__proto__', 'constructor', 'prototype'].includes(String(key).toLowerCase())) {
131
- throw new Error('Attempt to use prototype key disallowed');
139
+ if (
140
+ ["__proto__", "constructor", "prototype"].includes(
141
+ String(key).toLowerCase(),
142
+ )
143
+ ) {
144
+ throw new Error("Attempt to use prototype key disallowed");
132
145
  }
133
146
  return key;
134
147
  }
@@ -136,60 +149,64 @@ export function notProto(key) {
136
149
  /**
137
150
  * Validate a hook name.
138
151
  *
139
- * @access private
140
152
  * @param {string} hookName Hook name
141
153
  * @returns {void}
142
154
  * @throws {TypeError}
143
155
  * @throws {SyntaxError}
156
+ * @access private
144
157
  */
145
158
  export function validateHookName(hookName) {
146
- if (typeof hookName !== 'string') {
147
- throw new TypeError('Hook name must be a string');
159
+ if (typeof hookName !== "string") {
160
+ throw new TypeError("Hook name must be a string");
148
161
  }
149
162
 
150
163
  if (!hookName.length) {
151
- throw new SyntaxError('Hook name must not be empty');
164
+ throw new SyntaxError("Hook name must not be empty");
152
165
  }
153
166
 
154
167
  if (!hookName.match(/^([a-z_]+\.|)[a-z_]+$/i)) {
155
- throw new SyntaxError('Hook name must match either <scope>.<hookname> or <hookname> formats');
168
+ throw new SyntaxError(
169
+ "Hook name must match either <scope>.<hookname> or <hookname> formats",
170
+ );
156
171
  }
157
172
  }
158
173
 
159
174
  /**
160
175
  * Validate a hook path.
161
176
  *
162
- * @access private
163
177
  * @param {string} path URL path
164
178
  * @returns {void}
165
179
  * @throws {TypeError}
180
+ * @access private
166
181
  */
167
182
  export function validateHookPath(path) {
168
- if (typeof path !== 'string' && !(path instanceof RegExp)) {
169
- throw new TypeError('Hook path must be a string or RegExp');
183
+ if (typeof path !== "string" && !(path instanceof RegExp)) {
184
+ throw new TypeError("Hook path must be a string or RegExp");
170
185
  }
171
186
  }
172
187
 
173
188
  /**
174
189
  * Validate a URL path.
175
190
  *
176
- * @access private
177
191
  * @param {string} path URL path
178
192
  * @returns {string} Same string, if valid
179
193
  * @throws {TypeError}
180
194
  * @throws {SyntaxError}
195
+ * @access private
181
196
  */
182
197
  export function validateUrlPath(path) {
183
- if (typeof path !== 'string') {
184
- throw new TypeError('URL path must be a string');
198
+ if (typeof path !== "string") {
199
+ throw new TypeError("URL path must be a string");
185
200
  }
186
201
 
187
202
  if (path.match(/[^/a-z0-9_-]/)) {
188
- throw new SyntaxError('URL path must contain only a-z, 0-9, -, _ and / characters');
203
+ throw new SyntaxError(
204
+ "URL path must contain only a-z, 0-9, -, _ and / characters",
205
+ );
189
206
  }
190
207
 
191
208
  if (path.match(/\/{2,}/)) {
192
- throw new SyntaxError('URL path must not contain consecutive /');
209
+ throw new SyntaxError("URL path must not contain consecutive /");
193
210
  }
194
211
 
195
212
  return path;
@@ -198,45 +215,49 @@ export function validateUrlPath(path) {
198
215
  /**
199
216
  * Validate a template name.
200
217
  *
201
- * @access private
202
218
  * @param {string} view Template name
203
219
  * @returns {void}
204
220
  * @throws {TypeError}
205
221
  * @throws {SyntaxError}
222
+ * @access private
206
223
  */
207
224
  export function validateView(view) {
208
- if (typeof view !== 'string') {
209
- throw new TypeError('View must be a string');
225
+ if (typeof view !== "string") {
226
+ throw new TypeError("View must be a string");
210
227
  }
211
228
 
212
229
  if (!view.length) {
213
- throw new SyntaxError('View must not be empty');
230
+ throw new SyntaxError("View must not be empty");
214
231
  }
215
232
 
216
233
  if (!view.match(/^[a-z0-9/_-]+\.njk$/i)) {
217
- throw new SyntaxError('View must contain only a-z, 0-9, -, _ and / characters, and end in .njk');
234
+ throw new SyntaxError(
235
+ "View must contain only a-z, 0-9, -, _ and / characters, and end in .njk",
236
+ );
218
237
  }
219
238
  }
220
239
 
221
240
  /**
222
241
  * Validate a waypoint.
223
242
  *
224
- * @access private
225
243
  * @param {string} waypoint Waypoint
226
244
  * @returns {void}
227
245
  * @throws {TypeError}
228
246
  * @throws {SyntaxError}
247
+ * @access private
229
248
  */
230
249
  export function validateWaypoint(waypoint) {
231
- if (typeof waypoint !== 'string') {
232
- throw new TypeError('Waypoint must be a string');
250
+ if (typeof waypoint !== "string") {
251
+ throw new TypeError("Waypoint must be a string");
233
252
  }
234
253
 
235
254
  if (!waypoint.length) {
236
- throw new SyntaxError('Waypoint must not be empty');
255
+ throw new SyntaxError("Waypoint must not be empty");
237
256
  }
238
257
 
239
258
  if (waypoint.match(/[^/a-z0-9_-]/)) {
240
- throw new SyntaxError('Waypoint must contain only a-z, 0-9, -, _ and / characters');
259
+ throw new SyntaxError(
260
+ "Waypoint must contain only a-z, 0-9, -, _ and / characters",
261
+ );
241
262
  }
242
263
  }
@@ -1,37 +1,38 @@
1
1
  /* eslint-disable class-methods-use-this */
2
- import { DateTime } from 'luxon';
3
- import lodash from 'lodash';
4
- import ValidationError from '../ValidationError.js';
5
- import ValidatorFactory from '../ValidatorFactory.js';
6
- import { stringifyInput, stripWhitespace } from '../utils.js';
2
+ import { DateTime } from "luxon";
3
+ import lodash from "lodash";
4
+ import ValidationError from "../ValidationError.js";
5
+ import ValidatorFactory from "../ValidatorFactory.js";
6
+ import { stringifyInput, stripWhitespace } from "../utils.js";
7
7
 
8
8
  const { isPlainObject } = lodash;
9
9
 
10
10
  /**
11
+ * @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
11
12
  * @access private
12
- * @typedef {import('../../casa').ErrorMessageConfig} ErrorMessageConfig
13
13
  */
14
14
 
15
15
  /**
16
16
  * @typedef {object} DateObjectConfigOptions
17
17
  * @property {ErrorMessageConfig} errorMsg Error message config
18
18
  * @property {object} [afterOffsetFromNow] Offset from now
19
- * @property {ErrorMessageConfig} [errorMsgAfterOffset] Error if date is after this offset
19
+ * @property {ErrorMessageConfig} [errorMsgAfterOffset] Error if date is after
20
+ * this offset
20
21
  * @property {object} [beforeOffsetFromNow] Offset from now
21
- * @property {ErrorMessageConfig} [errorMsgBeforeOffset] Error if date is before this offset
22
- * @property {boolean} [allowMonthNames=false] Allow "Jan", "January", etc
23
- * @property {boolean} [allowSingleDigitDay=false] Allow "1" rather than "01"
24
- * @property {boolean} [allowSingleDigitMonth=false] Allow "1" rather than "01"
25
- * @property {DateTime} [now=false] Override the notion of "now" (useful for testing)
22
+ * @property {ErrorMessageConfig} [errorMsgBeforeOffset] Error if date is before
23
+ * this offset
24
+ * @property {boolean} [allowMonthNames=false] Allow "Jan", "January", etc.
25
+ * Default is `false`
26
+ * @property {boolean} [allowSingleDigitDay=false] Allow "1" rather than "01".
27
+ * Default is `false`
28
+ * @property {boolean} [allowSingleDigitMonth=false] Allow "1" rather than "01".
29
+ * Default is `false`
30
+ * @property {DateTime} [now=false] Override the notion of "now" (useful for
31
+ * testing). Default is `false`
26
32
  */
27
33
 
28
34
  /**
29
- * Date object format:
30
- * {
31
- * dd: <string>,
32
- * mm: <string>,
33
- * yyyy: <string>
34
- * }.
35
+ * Date object format: { dd: <string>, mm: <string>, yyyy: <string> }.
35
36
  *
36
37
  * Note that the time part will be zero'ed, as we are only interested in the
37
38
  * date component (minimum day resolution).
@@ -43,21 +44,21 @@ const { isPlainObject } = lodash;
43
44
  */
44
45
  export default class DateObject extends ValidatorFactory {
45
46
  /** @property {string} name Validator name ("dateObject") */
46
- name = 'dateObject';
47
+ name = "dateObject";
47
48
 
48
49
  validate(value, dataContext = {}) {
49
50
  const config = {
50
51
  errorMsg: {
51
- inline: 'validation:rule.dateObject.inline',
52
- summary: 'validation:rule.dateObject.summary',
52
+ inline: "validation:rule.dateObject.inline",
53
+ summary: "validation:rule.dateObject.summary",
53
54
  },
54
55
  errorMsgAfterOffset: {
55
- inline: 'validation:rule.dateObject.afterOffset.inline',
56
- summary: 'validation:rule.dateObject.afterOffset.summary',
56
+ inline: "validation:rule.dateObject.afterOffset.inline",
57
+ summary: "validation:rule.dateObject.afterOffset.summary",
57
58
  },
58
59
  errorMsgBeforeOffset: {
59
- inline: 'validation:rule.dateObject.beforeOffset.inline',
60
- summary: 'validation:rule.dateObject.beforeOffset.summary',
60
+ inline: "validation:rule.dateObject.beforeOffset.inline",
61
+ summary: "validation:rule.dateObject.beforeOffset.summary",
61
62
  },
62
63
  now: DateTime.local(),
63
64
  allowSingleDigitDay: false,
@@ -71,38 +72,44 @@ export default class DateObject extends ValidatorFactory {
71
72
  let valid = false;
72
73
  let { errorMsg } = config;
73
74
  let luxonDate;
74
- const NOW = config.now.startOf('day');
75
+ const NOW = config.now.startOf("day");
75
76
 
76
77
  // Accepted formats
77
- let formats = ['dd-MM-yyyy'];
78
- const formatTests = [{
79
- flags: [config.allowSingleDigitDay],
80
- formats: ['d-MM-yyyy'],
81
- }, {
82
- flags: [config.allowSingleDigitDay, config.allowSingleDigitMonth],
83
- formats: ['d-M-yyyy'],
84
- }, {
85
- flags: [config.allowSingleDigitDay, config.allowMonthNames],
86
- formats: ['d-MMM-yyyy', 'd-MMMM-yyyy'],
87
- }, {
88
- flags: [config.allowSingleDigitMonth],
89
- formats: ['dd-M-yyyy'],
90
- }, {
91
- flags: [config.allowMonthNames],
92
- formats: ['dd-MMM-yyyy', 'dd-MMMM-yyyy'],
93
- }];
78
+ let formats = ["dd-MM-yyyy"];
79
+ const formatTests = [
80
+ {
81
+ flags: [config.allowSingleDigitDay],
82
+ formats: ["d-MM-yyyy"],
83
+ },
84
+ {
85
+ flags: [config.allowSingleDigitDay, config.allowSingleDigitMonth],
86
+ formats: ["d-M-yyyy"],
87
+ },
88
+ {
89
+ flags: [config.allowSingleDigitDay, config.allowMonthNames],
90
+ formats: ["d-MMM-yyyy", "d-MMMM-yyyy"],
91
+ },
92
+ {
93
+ flags: [config.allowSingleDigitMonth],
94
+ formats: ["dd-M-yyyy"],
95
+ },
96
+ {
97
+ flags: [config.allowMonthNames],
98
+ formats: ["dd-MMM-yyyy", "dd-MMMM-yyyy"],
99
+ },
100
+ ];
94
101
  formatTests.forEach((test) => {
95
102
  if (test.flags.every((v) => v === true)) {
96
103
  formats = [...formats, ...test.formats];
97
104
  }
98
105
  });
99
106
 
100
- if (typeof value === 'object') {
107
+ if (typeof value === "object") {
101
108
  formats.find((format) => {
102
109
  luxonDate = DateTime.fromFormat(
103
- [value.dd, value.mm, value.yyyy].join('-'),
110
+ [value.dd, value.mm, value.yyyy].join("-"),
104
111
  format,
105
- ).startOf('day');
112
+ ).startOf("day");
106
113
 
107
114
  valid = luxonDate.isValid;
108
115
 
@@ -113,7 +120,7 @@ export default class DateObject extends ValidatorFactory {
113
120
  // Check date is after the specified duration from now.
114
121
  // Need to use UTC() otherwise DST shifts can affect the calculated offset
115
122
  if (config.afterOffsetFromNow) {
116
- const offsetDate = NOW.plus(config.afterOffsetFromNow).startOf('day');
123
+ const offsetDate = NOW.plus(config.afterOffsetFromNow).startOf("day");
117
124
 
118
125
  if (luxonDate <= offsetDate) {
119
126
  valid = false;
@@ -124,7 +131,9 @@ export default class DateObject extends ValidatorFactory {
124
131
  // Check date is before the specified duration from now
125
132
  // Need to use UTC() otherwise DST shifts can affect the calculated offset
126
133
  if (config.beforeOffsetFromNow) {
127
- const offsetDate = NOW.plus(config.beforeOffsetFromNow).startOf('day');
134
+ const offsetDate = NOW.plus(config.beforeOffsetFromNow).startOf(
135
+ "day",
136
+ );
128
137
 
129
138
  if (luxonDate >= offsetDate) {
130
139
  valid = false;
@@ -136,20 +145,20 @@ export default class DateObject extends ValidatorFactory {
136
145
  // Check presence of each object component (dd, mm, yyyy) in order to log
137
146
  // which specific parts are in error
138
147
  errorMsg.focusSuffix = [];
139
- if (!Object.prototype.hasOwnProperty.call(value, 'dd') || !value.dd) {
140
- errorMsg.focusSuffix.push('[dd]');
148
+ if (!Object.prototype.hasOwnProperty.call(value, "dd") || !value.dd) {
149
+ errorMsg.focusSuffix.push("[dd]");
141
150
  }
142
- if (!Object.prototype.hasOwnProperty.call(value, 'mm') || !value.mm) {
143
- errorMsg.focusSuffix.push('[mm]');
151
+ if (!Object.prototype.hasOwnProperty.call(value, "mm") || !value.mm) {
152
+ errorMsg.focusSuffix.push("[mm]");
144
153
  }
145
- if (!Object.prototype.hasOwnProperty.call(value, 'yyyy') || !value.yyyy) {
146
- errorMsg.focusSuffix.push('[yyyy]');
154
+ if (!Object.prototype.hasOwnProperty.call(value, "yyyy") || !value.yyyy) {
155
+ errorMsg.focusSuffix.push("[yyyy]");
147
156
  }
148
157
 
149
158
  // If the date is invalid, but not specific parts have been highlighted in
150
159
  // error, then highlight all inputs, focusing on the [dd] first
151
160
  if (!valid && !errorMsg.focusSuffix.length) {
152
- errorMsg.focusSuffix = ['[dd]', '[mm]', '[yyyy]'];
161
+ errorMsg.focusSuffix = ["[dd]", "[mm]", "[yyyy]"];
153
162
  }
154
163
  }
155
164
 
@@ -158,11 +167,13 @@ export default class DateObject extends ValidatorFactory {
158
167
 
159
168
  sanitise(value) {
160
169
  if (value !== undefined) {
161
- return isPlainObject(value) ? {
162
- dd: stripWhitespace(stringifyInput(value.dd)),
163
- mm: stripWhitespace(stringifyInput(value.mm)),
164
- yyyy: stripWhitespace(stringifyInput(value.yyyy)),
165
- } : Object.create(null);
170
+ return isPlainObject(value)
171
+ ? {
172
+ dd: stripWhitespace(stringifyInput(value.dd)),
173
+ mm: stripWhitespace(stringifyInput(value.mm)),
174
+ yyyy: stripWhitespace(stringifyInput(value.yyyy)),
175
+ }
176
+ : Object.create(null);
166
177
  }
167
178
  return undefined;
168
179
  }
@@ -1,14 +1,14 @@
1
1
  /* eslint-disable class-methods-use-this */
2
- import validatorPkg from 'validator';
3
- import ValidationError from '../ValidationError.js';
4
- import ValidatorFactory from '../ValidatorFactory.js';
5
- import { stringifyInput } from '../utils.js';
2
+ import validatorPkg from "validator";
3
+ import ValidationError from "../ValidationError.js";
4
+ import ValidatorFactory from "../ValidatorFactory.js";
5
+ import { stringifyInput } from "../utils.js";
6
6
 
7
7
  const { isEmail } = validatorPkg; // CommonJS
8
8
 
9
9
  /**
10
+ * @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
10
11
  * @access private
11
- * @typedef {import('../../casa').ErrorMessageConfig} ErrorMessageConfig
12
12
  */
13
13
 
14
14
  /**
@@ -28,7 +28,7 @@ const { isEmail } = validatorPkg; // CommonJS
28
28
  */
29
29
  export default class Email extends ValidatorFactory {
30
30
  /** @property {string} name Validator name ("email") */
31
- name = 'email';
31
+ name = "email";
32
32
 
33
33
  validate(value, dataContext = {}) {
34
34
  let isValid;
@@ -39,8 +39,8 @@ export default class Email extends ValidatorFactory {
39
39
  }
40
40
 
41
41
  const errorMsg = this.config.errorMsg || {
42
- summary: 'validation:rule.email.summary',
43
- inline: 'validation:rule.email.inline',
42
+ summary: "validation:rule.email.summary",
43
+ inline: "validation:rule.email.inline",
44
44
  };
45
45
 
46
46
  return isValid ? [] : [ValidationError.make({ errorMsg, dataContext })];
@@ -2,19 +2,18 @@
2
2
  /**
3
3
  * Test if a value is present in an array.
4
4
  *
5
- * Config options:
6
- * Array source = Array of values to test against
5
+ * Config options: Array source = Array of values to test against
7
6
  *
8
7
  * If the value itself is an array, all values within that array must be present
9
8
  * in the `source` array in order to pass validation.
10
9
  */
11
- import ValidationError from '../ValidationError.js';
12
- import ValidatorFactory from '../ValidatorFactory.js';
13
- import { stringifyInput, isStringable } from '../utils.js';
10
+ import ValidationError from "../ValidationError.js";
11
+ import ValidatorFactory from "../ValidatorFactory.js";
12
+ import { stringifyInput, isStringable } from "../utils.js";
14
13
 
15
14
  /**
15
+ * @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
16
16
  * @access private
17
- * @typedef {import('../../casa').ErrorMessageConfig} ErrorMessageConfig
18
17
  */
19
18
 
20
19
  /**
@@ -36,17 +35,17 @@ import { stringifyInput, isStringable } from '../utils.js';
36
35
  */
37
36
  export default class InArray extends ValidatorFactory {
38
37
  /** @property {string} name Validator name ("inArray") */
39
- name = 'inArray';
38
+ name = "inArray";
40
39
 
41
40
  validate(value, dataContext = {}) {
42
41
  let valid = false;
43
42
  const source = this.config.source || [];
44
43
  const errorMsg = this.config.errorMsg || {
45
- inline: 'validation:rule.inArray.inline',
46
- summary: 'validation:rule.inArray.summary',
44
+ inline: "validation:rule.inArray.inline",
45
+ summary: "validation:rule.inArray.summary",
47
46
  };
48
47
 
49
- if (value !== null && typeof value !== 'undefined') {
48
+ if (value !== null && typeof value !== "undefined") {
50
49
  const search = Array.isArray(value) ? value : [value];
51
50
  for (let i = 0, l = search.length; i < l; i += 1) {
52
51
  if (source.indexOf(search[parseInt(i, 10)]) > -1) {
@@ -62,7 +61,7 @@ export default class InArray extends ValidatorFactory {
62
61
  }
63
62
 
64
63
  sanitise(value) {
65
- const coerce = (val) => (stringifyInput(val, undefined));
64
+ const coerce = (val) => stringifyInput(val, undefined);
66
65
 
67
66
  // Basic stringable
68
67
  if (isStringable(value)) {
@@ -1,17 +1,15 @@
1
- import dateObject from './dateObject.js';
2
- import email from './email.js';
3
- import inArray from './inArray.js';
4
- import nino from './nino.js';
5
- import postalAddressObject from './postalAddressObject.js';
6
- import regex from './regex.js';
7
- import required from './required.js';
8
- import strlen from './strlen.js';
9
- import range from './range.js';
10
- import wordCount from './wordCount.js';
1
+ import dateObject from "./dateObject.js";
2
+ import email from "./email.js";
3
+ import inArray from "./inArray.js";
4
+ import nino from "./nino.js";
5
+ import postalAddressObject from "./postalAddressObject.js";
6
+ import regex from "./regex.js";
7
+ import required from "./required.js";
8
+ import strlen from "./strlen.js";
9
+ import range from "./range.js";
10
+ import wordCount from "./wordCount.js";
11
11
 
12
- /**
13
- * @namespace Validators
14
- */
12
+ /** @namespace Validators */
15
13
  export default {
16
14
  dateObject,
17
15
  email,
@@ -23,4 +21,4 @@ export default {
23
21
  strlen,
24
22
  range,
25
23
  wordCount,
26
- }
24
+ };