@dwp/govuk-casa 8.16.2 → 8.16.4

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 (189) hide show
  1. package/dist/assets/css/casa-ie8.css +1 -1
  2. package/dist/assets/css/casa.css +1 -1
  3. package/dist/casa.d.ts +13 -13
  4. package/dist/casa.js +17 -7
  5. package/dist/casa.js.map +1 -1
  6. package/dist/lib/CasaTemplateLoader.d.ts +1 -1
  7. package/dist/lib/CasaTemplateLoader.js +13 -14
  8. package/dist/lib/CasaTemplateLoader.js.map +1 -1
  9. package/dist/lib/JourneyContext.d.ts +10 -4
  10. package/dist/lib/JourneyContext.js +57 -47
  11. package/dist/lib/JourneyContext.js.map +1 -1
  12. package/dist/lib/MutableRouter.d.ts +1 -1
  13. package/dist/lib/MutableRouter.js +22 -23
  14. package/dist/lib/MutableRouter.js.map +1 -1
  15. package/dist/lib/Plan.d.ts +5 -5
  16. package/dist/lib/Plan.js +49 -36
  17. package/dist/lib/Plan.js.map +1 -1
  18. package/dist/lib/ValidationError.d.ts +1 -1
  19. package/dist/lib/ValidationError.js +9 -9
  20. package/dist/lib/ValidationError.js.map +1 -1
  21. package/dist/lib/ValidatorFactory.js +4 -7
  22. package/dist/lib/ValidatorFactory.js.map +1 -1
  23. package/dist/lib/configuration-ingestor.d.ts +75 -14
  24. package/dist/lib/configuration-ingestor.js +156 -64
  25. package/dist/lib/configuration-ingestor.js.map +1 -1
  26. package/dist/lib/configure.js +11 -10
  27. package/dist/lib/configure.js.map +1 -1
  28. package/dist/lib/constants.js +8 -8
  29. package/dist/lib/context-id-generators.d.ts +1 -1
  30. package/dist/lib/context-id-generators.js +7 -4
  31. package/dist/lib/context-id-generators.js.map +1 -1
  32. package/dist/lib/end-session.js +2 -2
  33. package/dist/lib/field.d.ts +6 -6
  34. package/dist/lib/field.js +15 -21
  35. package/dist/lib/field.js.map +1 -1
  36. package/dist/lib/index.d.ts +13 -13
  37. package/dist/lib/index.js +17 -7
  38. package/dist/lib/index.js.map +1 -1
  39. package/dist/lib/logger.js +7 -7
  40. package/dist/lib/logger.js.map +1 -1
  41. package/dist/lib/mount.js +3 -3
  42. package/dist/lib/mount.js.map +1 -1
  43. package/dist/lib/nunjucks-filters.d.ts +5 -1
  44. package/dist/lib/nunjucks-filters.js +37 -23
  45. package/dist/lib/nunjucks-filters.js.map +1 -1
  46. package/dist/lib/nunjucks.d.ts +2 -2
  47. package/dist/lib/nunjucks.js +6 -7
  48. package/dist/lib/nunjucks.js.map +1 -1
  49. package/dist/lib/utils.js +52 -42
  50. package/dist/lib/utils.js.map +1 -1
  51. package/dist/lib/validators/dateObject.d.ts +3 -3
  52. package/dist/lib/validators/dateObject.js +44 -37
  53. package/dist/lib/validators/dateObject.js.map +1 -1
  54. package/dist/lib/validators/email.d.ts +2 -2
  55. package/dist/lib/validators/email.js +4 -5
  56. package/dist/lib/validators/email.js.map +1 -1
  57. package/dist/lib/validators/inArray.d.ts +2 -2
  58. package/dist/lib/validators/inArray.js +5 -6
  59. package/dist/lib/validators/inArray.js.map +1 -1
  60. package/dist/lib/validators/index.d.ts +10 -10
  61. package/dist/lib/validators/index.js.map +1 -1
  62. package/dist/lib/validators/nino.d.ts +2 -2
  63. package/dist/lib/validators/nino.js +10 -7
  64. package/dist/lib/validators/nino.js.map +1 -1
  65. package/dist/lib/validators/postalAddressObject.d.ts +2 -2
  66. package/dist/lib/validators/postalAddressObject.js +52 -39
  67. package/dist/lib/validators/postalAddressObject.js.map +1 -1
  68. package/dist/lib/validators/range.d.ts +2 -2
  69. package/dist/lib/validators/range.js +6 -7
  70. package/dist/lib/validators/range.js.map +1 -1
  71. package/dist/lib/validators/regex.d.ts +2 -2
  72. package/dist/lib/validators/regex.js +4 -5
  73. package/dist/lib/validators/regex.js.map +1 -1
  74. package/dist/lib/validators/required.d.ts +2 -2
  75. package/dist/lib/validators/required.js +6 -9
  76. package/dist/lib/validators/required.js.map +1 -1
  77. package/dist/lib/validators/strlen.d.ts +2 -2
  78. package/dist/lib/validators/strlen.js +8 -9
  79. package/dist/lib/validators/strlen.js.map +1 -1
  80. package/dist/lib/validators/wordCount.d.ts +2 -2
  81. package/dist/lib/validators/wordCount.js +10 -9
  82. package/dist/lib/validators/wordCount.js.map +1 -1
  83. package/dist/lib/waypoint-url.d.ts +4 -4
  84. package/dist/lib/waypoint-url.js +23 -23
  85. package/dist/lib/waypoint-url.js.map +1 -1
  86. package/dist/middleware/body-parser.d.ts +27 -5
  87. package/dist/middleware/body-parser.js +37 -6
  88. package/dist/middleware/body-parser.js.map +1 -1
  89. package/dist/middleware/csrf.d.ts +3 -0
  90. package/dist/middleware/csrf.js +3 -0
  91. package/dist/middleware/csrf.js.map +1 -1
  92. package/dist/middleware/data.d.ts +22 -5
  93. package/dist/middleware/data.js +37 -7
  94. package/dist/middleware/data.js.map +1 -1
  95. package/dist/middleware/gather-fields.d.ts +1 -1
  96. package/dist/middleware/gather-fields.js +4 -3
  97. package/dist/middleware/gather-fields.js.map +1 -1
  98. package/dist/middleware/i18n.d.ts +11 -2
  99. package/dist/middleware/i18n.js +26 -17
  100. package/dist/middleware/i18n.js.map +1 -1
  101. package/dist/middleware/post.d.ts +3 -1
  102. package/dist/middleware/post.js +35 -18
  103. package/dist/middleware/post.js.map +1 -1
  104. package/dist/middleware/pre.d.ts +1 -1
  105. package/dist/middleware/pre.js +43 -21
  106. package/dist/middleware/pre.js.map +1 -1
  107. package/dist/middleware/progress-journey.d.ts +1 -1
  108. package/dist/middleware/progress-journey.js +5 -5
  109. package/dist/middleware/progress-journey.js.map +1 -1
  110. package/dist/middleware/sanitise-fields.d.ts +2 -2
  111. package/dist/middleware/sanitise-fields.js +13 -11
  112. package/dist/middleware/sanitise-fields.js.map +1 -1
  113. package/dist/middleware/serve-first-waypoint.d.ts +1 -1
  114. package/dist/middleware/serve-first-waypoint.js +6 -4
  115. package/dist/middleware/serve-first-waypoint.js.map +1 -1
  116. package/dist/middleware/session.d.ts +27 -8
  117. package/dist/middleware/session.js +53 -25
  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 +15 -13
  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 +2 -2
  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 +2 -2
  132. package/dist/routes/ancillary.js +3 -3
  133. package/dist/routes/ancillary.js.map +1 -1
  134. package/dist/routes/journey.d.ts +1 -1
  135. package/dist/routes/journey.js +85 -31
  136. package/dist/routes/journey.js.map +1 -1
  137. package/dist/routes/static.d.ts +13 -4
  138. package/dist/routes/static.js +21 -19
  139. package/dist/routes/static.js.map +1 -1
  140. package/package.json +33 -36
  141. package/src/casa.js +13 -13
  142. package/src/lib/CasaTemplateLoader.js +21 -17
  143. package/src/lib/JourneyContext.js +118 -79
  144. package/src/lib/MutableRouter.js +30 -26
  145. package/src/lib/Plan.js +109 -62
  146. package/src/lib/ValidationError.js +13 -10
  147. package/src/lib/ValidatorFactory.js +7 -8
  148. package/src/lib/configuration-ingestor.js +200 -74
  149. package/src/lib/configure.js +31 -30
  150. package/src/lib/constants.js +8 -8
  151. package/src/lib/context-id-generators.js +39 -38
  152. package/src/lib/end-session.js +3 -3
  153. package/src/lib/field.js +48 -32
  154. package/src/lib/index.js +12 -12
  155. package/src/lib/logger.js +9 -9
  156. package/src/lib/mount.js +68 -73
  157. package/src/lib/nunjucks-filters.js +57 -44
  158. package/src/lib/nunjucks.js +20 -16
  159. package/src/lib/utils.js +69 -44
  160. package/src/lib/validators/dateObject.js +57 -48
  161. package/src/lib/validators/email.js +8 -9
  162. package/src/lib/validators/inArray.js +8 -9
  163. package/src/lib/validators/index.js +11 -11
  164. package/src/lib/validators/nino.js +25 -12
  165. package/src/lib/validators/postalAddressObject.js +73 -55
  166. package/src/lib/validators/range.js +9 -11
  167. package/src/lib/validators/regex.js +7 -8
  168. package/src/lib/validators/required.js +13 -14
  169. package/src/lib/validators/strlen.js +11 -12
  170. package/src/lib/validators/wordCount.js +17 -12
  171. package/src/lib/waypoint-url.js +48 -33
  172. package/src/middleware/body-parser.js +44 -10
  173. package/src/middleware/csrf.js +4 -1
  174. package/src/middleware/data.js +62 -25
  175. package/src/middleware/gather-fields.js +8 -8
  176. package/src/middleware/i18n.js +49 -39
  177. package/src/middleware/post.js +47 -21
  178. package/src/middleware/pre.js +59 -35
  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 +12 -10
  182. package/src/middleware/session.js +97 -65
  183. package/src/middleware/skip-waypoint.js +7 -9
  184. package/src/middleware/steer-journey.js +39 -27
  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 +4 -6
  188. package/src/routes/journey.js +158 -78
  189. package/src/routes/static.js +64 -26
@@ -1,6 +1,6 @@
1
- import merge from 'deepmerge';
2
- import { DateTime } from 'luxon';
3
- import nunjucks from 'nunjucks';
1
+ import merge from "deepmerge";
2
+ import { DateTime } from "luxon";
3
+ import nunjucks from "nunjucks";
4
4
 
5
5
  const { all: deepmergeAll } = merge;
6
6
 
@@ -9,54 +9,66 @@ const { all: deepmergeAll } = merge;
9
9
  // ref: https://www.npmjs.com/package/deepmerge
10
10
 
11
11
  const combineMerge = (target, source, options) => {
12
- const destination = target.slice()
12
+ const destination = target.slice();
13
13
 
14
14
  source.forEach((item, index) => {
15
15
  // ESLint disabled as `index` is only an integer
16
16
  /* eslint-disable security/detect-object-injection */
17
- if (typeof destination[index] === 'undefined') {
18
- destination[index] = options.cloneUnlessOtherwiseSpecified(item, options)
17
+ if (typeof destination[index] === "undefined") {
18
+ destination[index] = options.cloneUnlessOtherwiseSpecified(item, options);
19
19
  } else if (options.isMergeableObject(item)) {
20
- destination[index] = merge(target[index], item, options)
20
+ destination[index] = merge(target[index], item, options);
21
21
  } else if (target.indexOf(item) === -1) {
22
- destination.push(item)
22
+ destination.push(item);
23
23
  }
24
24
  /* eslint-enable security/detect-object-injection */
25
- })
26
- return destination
27
- }
25
+ });
26
+ return destination;
27
+ };
28
28
 
29
29
  // Allows objects to be deepmerged and retain their type, without becoming [object Object]
30
30
  // ref: https://github.com/jonschlinkert/is-plain-object/blob/master/is-plain-object.js
31
31
 
32
+ /**
33
+ * @param {any} o Value to test
34
+ * @returns {boolean} True if an object
35
+ */
32
36
  function isObject(o) {
33
- return Object.prototype.toString.call(o) === '[object Object]';
37
+ return Object.prototype.toString.call(o) === "[object Object]";
34
38
  }
35
39
 
40
+ /**
41
+ * @param {any} o Value to test
42
+ * @returns {boolean} True if a plain object or array
43
+ */
36
44
  function isPlainObjectOrArray(o) {
37
45
  if (Array.isArray(o)) {
38
- return true
46
+ return true;
39
47
  }
40
48
  if (isObject(o) === false) {
41
- return false
49
+ return false;
42
50
  }
43
51
  const ctor = o.constructor;
44
52
  if (ctor === undefined) {
45
- return true
53
+ return true;
46
54
  }
47
55
  const prot = ctor.prototype;
48
56
  if (isObject(prot) === false) {
49
- return false
57
+ return false;
50
58
  }
51
59
  // eslint-disable-next-line no-prototype-builtins
52
- return prot.hasOwnProperty('isPrototypeOf');
60
+ return prot.hasOwnProperty("isPrototypeOf");
53
61
  }
54
62
 
63
+ /**
64
+ * @param {...any} objects Objects to merge
65
+ * @returns {object} Merged object
66
+ */
55
67
  function mergeObjects(...objects) {
56
- return deepmergeAll([
57
- Object.create(null),
58
- ...objects,
59
- ], { arrayMerge: combineMerge, isMergeableObject: isPlainObjectOrArray });
68
+ return deepmergeAll([Object.create(null), ...objects], {
69
+ arrayMerge: combineMerge,
70
+ isMergeableObject: isPlainObjectOrArray,
71
+ });
60
72
  }
61
73
  /**
62
74
  * Determine whether a value exists in a list.
@@ -66,7 +78,7 @@ function mergeObjects(...objects) {
66
78
  * @param {any} search Item to search within the `source`
67
79
  * @returns {boolean} True if the search item was found
68
80
  */
69
- function includes(source = [], search = '') {
81
+ function includes(source = [], search = "") {
70
82
  return source.includes(search);
71
83
  }
72
84
 
@@ -89,21 +101,23 @@ function includes(source = [], search = '') {
89
101
  * @returns {string} Formatted date
90
102
  */
91
103
  function formatDateObject(date, config = {}) {
92
- const { locale = 'en', format = 'd MMMM yyyy' } = config;
104
+ const { locale = "en", format = "d MMMM yyyy" } = config;
93
105
 
94
106
  if (
95
- Object.prototype.toString.call(date) === '[object Object]'
96
- && 'yyyy' in date
97
- && 'mm' in date
98
- && 'dd' in date
107
+ Object.prototype.toString.call(date) === "[object Object]" &&
108
+ "yyyy" in date &&
109
+ "mm" in date &&
110
+ "dd" in date
99
111
  ) {
100
112
  return DateTime.fromObject({
101
113
  year: Math.max(0, parseInt(date.yyyy, 10)),
102
114
  month: Math.max(0, parseInt(date.mm, 10)),
103
115
  day: Math.max(1, parseInt(date.dd, 10)),
104
- }).setLocale(locale).toFormat(format);
116
+ })
117
+ .setLocale(locale)
118
+ .toFormat(format);
105
119
  }
106
- return 'INVALID DATE OBJECT';
120
+ return "INVALID DATE OBJECT";
107
121
  }
108
122
 
109
123
  /**
@@ -119,32 +133,31 @@ function formatDateObject(date, config = {}) {
119
133
  */
120
134
  function renderAsAttributes(attrsObject) {
121
135
  const attrsList = [];
122
- if (typeof attrsObject === 'object') {
136
+ if (typeof attrsObject === "object") {
123
137
  Object.keys(attrsObject).forEach((key) => {
124
138
  // ESLint disable as `attrsObject` is dev-controlled, `Object.keys()` has
125
139
  // been used (to get "own" properties) and `m` is one of the characters
126
140
  // found by the regex.
127
141
  /* eslint-disable security/detect-object-injection */
128
- const value = String(attrsObject[key]).replace(/[<>"'&]/g, (m) => ({
129
- '<': '&lt;',
130
- '>': '&gt;',
131
- '"': '&quot;',
132
- '\'': '&#039;',
133
- '&': '&amp;',
134
- }[m]));
142
+ const value = String(attrsObject[key]).replace(
143
+ /[<>"'&]/g,
144
+ (m) =>
145
+ ({
146
+ "<": "&lt;",
147
+ ">": "&gt;",
148
+ '"': "&quot;",
149
+ "'": "&#039;",
150
+ "&": "&amp;",
151
+ })[m],
152
+ );
135
153
  /* eslint-enable security/detect-object-injection */
136
154
  attrsList.push(`${key}="${value}"`);
137
155
  });
138
156
  }
139
- return new nunjucks.runtime.SafeString(attrsList.join(' '));
157
+ return new nunjucks.runtime.SafeString(attrsList.join(" "));
140
158
  }
141
159
 
142
160
  /**
143
161
  * @namespace NunjucksFilters
144
162
  */
145
- export {
146
- mergeObjects,
147
- includes,
148
- formatDateObject,
149
- renderAsAttributes,
150
- };
163
+ export { mergeObjects, includes, formatDateObject, renderAsAttributes };
@@ -1,11 +1,14 @@
1
- import { readFileSync } from 'fs';
2
- import { resolve } from 'path';
3
- import { Environment } from 'nunjucks';
4
- import dirname from './dirname.cjs';
5
- import CasaTemplateLoader from './CasaTemplateLoader.js';
1
+ import { readFileSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { Environment } from "nunjucks";
4
+ import dirname from "./dirname.cjs";
5
+ import CasaTemplateLoader from "./CasaTemplateLoader.js";
6
6
  import {
7
- mergeObjects, includes, renderAsAttributes, formatDateObject,
8
- } from './nunjucks-filters.js';
7
+ mergeObjects,
8
+ includes,
9
+ renderAsAttributes,
10
+ formatDateObject,
11
+ } from "./nunjucks-filters.js";
9
12
 
10
13
  /**
11
14
  * @typedef {object} NunjucksOptions
@@ -19,9 +22,7 @@ import {
19
22
  * @param {NunjucksOptions} options Nunjucks options
20
23
  * @returns {Environment} Nunjucks Environment instance
21
24
  */
22
- export default function nunjucksConfig({
23
- views = [],
24
- }) {
25
+ export default function nunjucksConfig({ views = [] }) {
25
26
  // Prepare a single Nunjucks environment for all responses to use. Note that
26
27
  // we cannot prepare response-specific global functions/filters if we use a
27
28
  // single environment, but the performance gains of doing so are significant.
@@ -42,13 +43,16 @@ export default function nunjucksConfig({
42
43
 
43
44
  // Globals
44
45
  // These can't be modified once set. But they can be overridden by res.locals.
45
- /* eslint-disable-next-line security/detect-non-literal-fs-filename */
46
- env.addGlobal('casaVersion', JSON.parse(readFileSync(resolve(dirname, '../../package.json'))).version);
47
46
 
48
- env.addGlobal('mergeObjects', mergeObjects);
49
- env.addGlobal('includes', includes);
50
- env.addGlobal('formatDateObject', formatDateObject);
51
- env.addGlobal('renderAsAttributes', renderAsAttributes);
47
+ env.addGlobal(
48
+ "casaVersion",
49
+ JSON.parse(readFileSync(resolve(dirname, "../../package.json"))).version,
50
+ );
51
+
52
+ env.addGlobal("mergeObjects", mergeObjects);
53
+ env.addGlobal("includes", includes);
54
+ env.addGlobal("formatDateObject", formatDateObject);
55
+ env.addGlobal("renderAsAttributes", renderAsAttributes);
52
56
 
53
57
  return env;
54
58
  }
package/src/lib/utils.js CHANGED
@@ -12,13 +12,13 @@
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;
@@ -34,7 +34,7 @@ export function isEmpty(val) {
34
34
  * @returns {boolean} Whether the value is stringable or not
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
  /**
@@ -48,9 +48,14 @@ export function isStringable(value) {
48
48
  * @returns {Function[]} An array of middleware that should be applied
49
49
  */
50
50
  export function resolveMiddlewareHooks(hookName, path, hooks = []) {
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);
51
+ const pathMatch = (h) =>
52
+ h.path === undefined ||
53
+ (h.path instanceof RegExp && h.path.test(path)) ||
54
+ h.path === path;
55
+ return hooks
56
+ .filter((h) => h.hook === hookName)
57
+ .filter(pathMatch)
58
+ .map((h) => h.middleware);
54
59
  }
55
60
 
56
61
  /**
@@ -63,7 +68,10 @@ export function resolveMiddlewareHooks(hookName, path, hooks = []) {
63
68
  */
64
69
  export function stringifyInput(input, fallback) {
65
70
  // Not using param defaults here as the fallback may be explicitly "undefined"
66
- const fb = arguments.length === 2 && (isStringable(fallback) || fallback === undefined) ? fallback : '';
71
+ const fb =
72
+ arguments.length === 2 && (isStringable(fallback) || fallback === undefined)
73
+ ? fallback
74
+ : "";
67
75
  return isStringable(input) ? String(input) : fb;
68
76
  }
69
77
 
@@ -88,32 +96,37 @@ export function coerceInputToInteger(input) {
88
96
  */
89
97
  export function stripWhitespace(value, options) {
90
98
  const opts = {
91
- leading: '',
92
- trailing: '',
93
- nested: ' ',
99
+ leading: "",
100
+ trailing: "",
101
+ nested: " ",
94
102
  ...options,
95
103
  };
96
104
 
97
- if (typeof value !== 'string') {
98
- throw new TypeError('value must be a string');
105
+ if (typeof value !== "string") {
106
+ throw new TypeError("value must be a string");
99
107
  }
100
108
 
101
- if (typeof opts.leading !== 'string') {
102
- throw new TypeError('leading must be a string');
109
+ if (typeof opts.leading !== "string") {
110
+ throw new TypeError("leading must be a string");
103
111
  }
104
112
 
105
- if (typeof opts.trailing !== 'string') {
106
- throw new TypeError('trailing must be a string');
113
+ if (typeof opts.trailing !== "string") {
114
+ throw new TypeError("trailing must be a string");
107
115
  }
108
116
 
109
- if (typeof opts.nested !== 'string') {
110
- throw new TypeError('nested must be a string');
117
+ if (typeof opts.nested !== "string") {
118
+ throw new TypeError("nested must be a string");
111
119
  }
112
120
 
113
- return value
114
- .replace(/^\s+/, opts.leading)
115
- .replace(/\s+$/, opts.trailing)
116
- .replace(/\s+/g, opts.nested);
121
+ // This approach avoids using `/s+$/` regex, which triggers the
122
+ // `sonarjs/slow-regex` eslint rule
123
+ let newValue = value.replace(/^\s+/, opts.leading);
124
+ if (newValue.match(/\s$/)) {
125
+ newValue = `${newValue.trimEnd()}${opts.trailing}`;
126
+ }
127
+ newValue = newValue.replace(/\s+/g, opts.nested);
128
+
129
+ return newValue;
117
130
  }
118
131
 
119
132
  /* ------------------------------------------------ validation / sanitisation */
@@ -127,8 +140,12 @@ export function stripWhitespace(value, options) {
127
140
  * @throws {Error} if proposed key is an invalid keyword
128
141
  */
129
142
  export function notProto(key) {
130
- if (['__proto__', 'constructor', 'prototype'].includes(String(key).toLowerCase())) {
131
- throw new Error('Attempt to use prototype key disallowed');
143
+ if (
144
+ ["__proto__", "constructor", "prototype"].includes(
145
+ String(key).toLowerCase(),
146
+ )
147
+ ) {
148
+ throw new Error("Attempt to use prototype key disallowed");
132
149
  }
133
150
  return key;
134
151
  }
@@ -143,16 +160,18 @@ export function notProto(key) {
143
160
  * @throws {SyntaxError}
144
161
  */
145
162
  export function validateHookName(hookName) {
146
- if (typeof hookName !== 'string') {
147
- throw new TypeError('Hook name must be a string');
163
+ if (typeof hookName !== "string") {
164
+ throw new TypeError("Hook name must be a string");
148
165
  }
149
166
 
150
167
  if (!hookName.length) {
151
- throw new SyntaxError('Hook name must not be empty');
168
+ throw new SyntaxError("Hook name must not be empty");
152
169
  }
153
170
 
154
171
  if (!hookName.match(/^([a-z_]+\.|)[a-z_]+$/i)) {
155
- throw new SyntaxError('Hook name must match either <scope>.<hookname> or <hookname> formats');
172
+ throw new SyntaxError(
173
+ "Hook name must match either <scope>.<hookname> or <hookname> formats",
174
+ );
156
175
  }
157
176
  }
158
177
 
@@ -165,8 +184,8 @@ export function validateHookName(hookName) {
165
184
  * @throws {TypeError}
166
185
  */
167
186
  export function validateHookPath(path) {
168
- if (typeof path !== 'string' && !(path instanceof RegExp)) {
169
- throw new TypeError('Hook path must be a string or RegExp');
187
+ if (typeof path !== "string" && !(path instanceof RegExp)) {
188
+ throw new TypeError("Hook path must be a string or RegExp");
170
189
  }
171
190
  }
172
191
 
@@ -180,16 +199,18 @@ export function validateHookPath(path) {
180
199
  * @throws {SyntaxError}
181
200
  */
182
201
  export function validateUrlPath(path) {
183
- if (typeof path !== 'string') {
184
- throw new TypeError('URL path must be a string');
202
+ if (typeof path !== "string") {
203
+ throw new TypeError("URL path must be a string");
185
204
  }
186
205
 
187
206
  if (path.match(/[^/a-z0-9_-]/)) {
188
- throw new SyntaxError('URL path must contain only a-z, 0-9, -, _ and / characters');
207
+ throw new SyntaxError(
208
+ "URL path must contain only a-z, 0-9, -, _ and / characters",
209
+ );
189
210
  }
190
211
 
191
212
  if (path.match(/\/{2,}/)) {
192
- throw new SyntaxError('URL path must not contain consecutive /');
213
+ throw new SyntaxError("URL path must not contain consecutive /");
193
214
  }
194
215
 
195
216
  return path;
@@ -205,16 +226,18 @@ export function validateUrlPath(path) {
205
226
  * @throws {SyntaxError}
206
227
  */
207
228
  export function validateView(view) {
208
- if (typeof view !== 'string') {
209
- throw new TypeError('View must be a string');
229
+ if (typeof view !== "string") {
230
+ throw new TypeError("View must be a string");
210
231
  }
211
232
 
212
233
  if (!view.length) {
213
- throw new SyntaxError('View must not be empty');
234
+ throw new SyntaxError("View must not be empty");
214
235
  }
215
236
 
216
237
  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');
238
+ throw new SyntaxError(
239
+ "View must contain only a-z, 0-9, -, _ and / characters, and end in .njk",
240
+ );
218
241
  }
219
242
  }
220
243
 
@@ -228,15 +251,17 @@ export function validateView(view) {
228
251
  * @throws {SyntaxError}
229
252
  */
230
253
  export function validateWaypoint(waypoint) {
231
- if (typeof waypoint !== 'string') {
232
- throw new TypeError('Waypoint must be a string');
254
+ if (typeof waypoint !== "string") {
255
+ throw new TypeError("Waypoint must be a string");
233
256
  }
234
257
 
235
258
  if (!waypoint.length) {
236
- throw new SyntaxError('Waypoint must not be empty');
259
+ throw new SyntaxError("Waypoint must not be empty");
237
260
  }
238
261
 
239
262
  if (waypoint.match(/[^/a-z0-9_-]/)) {
240
- throw new SyntaxError('Waypoint must contain only a-z, 0-9, -, _ and / characters');
263
+ throw new SyntaxError(
264
+ "Waypoint must contain only a-z, 0-9, -, _ and / characters",
265
+ );
241
266
  }
242
267
  }
@@ -1,9 +1,8 @@
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';
1
+ import { DateTime } from "luxon";
2
+ import lodash from "lodash";
3
+ import ValidationError from "../ValidationError.js";
4
+ import ValidatorFactory from "../ValidatorFactory.js";
5
+ import { stringifyInput, stripWhitespace } from "../utils.js";
7
6
 
8
7
  const { isPlainObject } = lodash;
9
8
 
@@ -43,21 +42,21 @@ const { isPlainObject } = lodash;
43
42
  */
44
43
  export default class DateObject extends ValidatorFactory {
45
44
  /** @property {string} name Validator name ("dateObject") */
46
- name = 'dateObject';
45
+ name = "dateObject";
47
46
 
48
47
  validate(value, dataContext = {}) {
49
48
  const config = {
50
49
  errorMsg: {
51
- inline: 'validation:rule.dateObject.inline',
52
- summary: 'validation:rule.dateObject.summary',
50
+ inline: "validation:rule.dateObject.inline",
51
+ summary: "validation:rule.dateObject.summary",
53
52
  },
54
53
  errorMsgAfterOffset: {
55
- inline: 'validation:rule.dateObject.afterOffset.inline',
56
- summary: 'validation:rule.dateObject.afterOffset.summary',
54
+ inline: "validation:rule.dateObject.afterOffset.inline",
55
+ summary: "validation:rule.dateObject.afterOffset.summary",
57
56
  },
58
57
  errorMsgBeforeOffset: {
59
- inline: 'validation:rule.dateObject.beforeOffset.inline',
60
- summary: 'validation:rule.dateObject.beforeOffset.summary',
58
+ inline: "validation:rule.dateObject.beforeOffset.inline",
59
+ summary: "validation:rule.dateObject.beforeOffset.summary",
61
60
  },
62
61
  now: DateTime.local(),
63
62
  allowSingleDigitDay: false,
@@ -71,38 +70,44 @@ export default class DateObject extends ValidatorFactory {
71
70
  let valid = false;
72
71
  let { errorMsg } = config;
73
72
  let luxonDate;
74
- const NOW = config.now.startOf('day');
73
+ const NOW = config.now.startOf("day");
75
74
 
76
75
  // 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
- }];
76
+ let formats = ["dd-MM-yyyy"];
77
+ const formatTests = [
78
+ {
79
+ flags: [config.allowSingleDigitDay],
80
+ formats: ["d-MM-yyyy"],
81
+ },
82
+ {
83
+ flags: [config.allowSingleDigitDay, config.allowSingleDigitMonth],
84
+ formats: ["d-M-yyyy"],
85
+ },
86
+ {
87
+ flags: [config.allowSingleDigitDay, config.allowMonthNames],
88
+ formats: ["d-MMM-yyyy", "d-MMMM-yyyy"],
89
+ },
90
+ {
91
+ flags: [config.allowSingleDigitMonth],
92
+ formats: ["dd-M-yyyy"],
93
+ },
94
+ {
95
+ flags: [config.allowMonthNames],
96
+ formats: ["dd-MMM-yyyy", "dd-MMMM-yyyy"],
97
+ },
98
+ ];
94
99
  formatTests.forEach((test) => {
95
100
  if (test.flags.every((v) => v === true)) {
96
101
  formats = [...formats, ...test.formats];
97
102
  }
98
103
  });
99
104
 
100
- if (typeof value === 'object') {
105
+ if (typeof value === "object") {
101
106
  formats.find((format) => {
102
107
  luxonDate = DateTime.fromFormat(
103
- [value.dd, value.mm, value.yyyy].join('-'),
108
+ [value.dd, value.mm, value.yyyy].join("-"),
104
109
  format,
105
- ).startOf('day');
110
+ ).startOf("day");
106
111
 
107
112
  valid = luxonDate.isValid;
108
113
 
@@ -113,7 +118,7 @@ export default class DateObject extends ValidatorFactory {
113
118
  // Check date is after the specified duration from now.
114
119
  // Need to use UTC() otherwise DST shifts can affect the calculated offset
115
120
  if (config.afterOffsetFromNow) {
116
- const offsetDate = NOW.plus(config.afterOffsetFromNow).startOf('day');
121
+ const offsetDate = NOW.plus(config.afterOffsetFromNow).startOf("day");
117
122
 
118
123
  if (luxonDate <= offsetDate) {
119
124
  valid = false;
@@ -124,7 +129,9 @@ export default class DateObject extends ValidatorFactory {
124
129
  // Check date is before the specified duration from now
125
130
  // Need to use UTC() otherwise DST shifts can affect the calculated offset
126
131
  if (config.beforeOffsetFromNow) {
127
- const offsetDate = NOW.plus(config.beforeOffsetFromNow).startOf('day');
132
+ const offsetDate = NOW.plus(config.beforeOffsetFromNow).startOf(
133
+ "day",
134
+ );
128
135
 
129
136
  if (luxonDate >= offsetDate) {
130
137
  valid = false;
@@ -136,20 +143,20 @@ export default class DateObject extends ValidatorFactory {
136
143
  // Check presence of each object component (dd, mm, yyyy) in order to log
137
144
  // which specific parts are in error
138
145
  errorMsg.focusSuffix = [];
139
- if (!Object.prototype.hasOwnProperty.call(value, 'dd') || !value.dd) {
140
- errorMsg.focusSuffix.push('[dd]');
146
+ if (!Object.prototype.hasOwnProperty.call(value, "dd") || !value.dd) {
147
+ errorMsg.focusSuffix.push("[dd]");
141
148
  }
142
- if (!Object.prototype.hasOwnProperty.call(value, 'mm') || !value.mm) {
143
- errorMsg.focusSuffix.push('[mm]');
149
+ if (!Object.prototype.hasOwnProperty.call(value, "mm") || !value.mm) {
150
+ errorMsg.focusSuffix.push("[mm]");
144
151
  }
145
- if (!Object.prototype.hasOwnProperty.call(value, 'yyyy') || !value.yyyy) {
146
- errorMsg.focusSuffix.push('[yyyy]');
152
+ if (!Object.prototype.hasOwnProperty.call(value, "yyyy") || !value.yyyy) {
153
+ errorMsg.focusSuffix.push("[yyyy]");
147
154
  }
148
155
 
149
156
  // If the date is invalid, but not specific parts have been highlighted in
150
157
  // error, then highlight all inputs, focusing on the [dd] first
151
158
  if (!valid && !errorMsg.focusSuffix.length) {
152
- errorMsg.focusSuffix = ['[dd]', '[mm]', '[yyyy]'];
159
+ errorMsg.focusSuffix = ["[dd]", "[mm]", "[yyyy]"];
153
160
  }
154
161
  }
155
162
 
@@ -158,11 +165,13 @@ export default class DateObject extends ValidatorFactory {
158
165
 
159
166
  sanitise(value) {
160
167
  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);
168
+ return isPlainObject(value)
169
+ ? {
170
+ dd: stripWhitespace(stringifyInput(value.dd)),
171
+ mm: stripWhitespace(stringifyInput(value.mm)),
172
+ yyyy: stripWhitespace(stringifyInput(value.yyyy)),
173
+ }
174
+ : Object.create(null);
166
175
  }
167
176
  return undefined;
168
177
  }