@dwp/govuk-casa 8.16.2 → 8.16.3

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 +44 -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 +2 -2
  138. package/dist/routes/static.js +18 -18
  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 +60 -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 +61 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwp/govuk-casa",
3
- "version": "8.16.2",
3
+ "version": "8.16.3",
4
4
  "description": "A framework for building GOVUK Collect-And-Submit-Applications",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,8 +20,8 @@
20
20
  "views/**/*"
21
21
  ],
22
22
  "engines": {
23
- "node": "^18.0.0 || ^20.0.0",
24
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
23
+ "node": ">=18 <=22",
24
+ "npm": ">=8 <=10"
25
25
  },
26
26
  "scripts": {
27
27
  "pipeline": "npm run coverage && npm run lint",
@@ -31,7 +31,7 @@
31
31
  "test:e2e": "spiderplan --worker-init ./tests/e2e/worker-init.js --language en ./tests/e2e/personas/**/*.yaml",
32
32
  "test:dast": "spiderplan --worker-init ./tests/e2e/worker-init.js --language en ./tests/e2e/personas/**/traversal.yaml --workers 1 --zap --zap-proxy 'http://localhost:8080/' --zap-target-hostname 'host.docker.internal'",
33
33
  "test:dast:report": "curl -s --header 'X-ZAP-Api-Key: secret' http://localhost:8080/OTHER/core/other/htmlreport > gl-dast-report.html",
34
- "test:dast:setup": "docker run --rm --name casa-dast -d -u zap -p 8080:8080 -i owasp/zap2docker-stable zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.addrs.addr.name=\".*\" -config api.addrs.addr.regex=true -config api.key=secret; npm run test:dast:ready-check",
34
+ "test:dast:setup": "docker run --rm --name casa-dast -d -u zap -p 8080:8080 -i ghcr.io/zaproxy/zaproxy:bare@sha256:24a4037a3e8607d9fedbd75e4a7f1336d11998e1c331aab9991ef074f5de4b22 zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.addrs.addr.name=\".*\" -config api.addrs.addr.regex=true -config api.key=secret -notel; npm run test:dast:ready-check",
35
35
  "test:dast:ready-check": "while [ \"$(curl -Is -o /dev/null -w %{response_code} http://localhost:8080/)\" -ne \"200\" ]; do sleep 1; echo 'Waiting for ZAP to start ...'; done",
36
36
  "test:dast:teardown": "docker stop casa-dast",
37
37
  "lint": "eslint .",
@@ -52,14 +52,14 @@
52
52
  "bytes": "3.1.2",
53
53
  "cookie-parser": "1.4.7",
54
54
  "csrf-sync": "4.0.3",
55
- "debug": "4.3.7",
55
+ "debug": "4.4.0",
56
56
  "deepmerge": "4.3.1",
57
- "express": "4.21.1",
57
+ "express": "4.21.2",
58
58
  "express-session": "1.18.1",
59
59
  "govuk-frontend": "4.9.0",
60
- "helmet": "7.1.0",
61
- "i18next": "23.15.2",
62
- "i18next-http-middleware": "3.6.0",
60
+ "helmet": "8.0.0",
61
+ "i18next": "24.2.0",
62
+ "i18next-http-middleware": "3.7.0",
63
63
  "js-yaml": "4.1.0",
64
64
  "lodash": "4.17.21",
65
65
  "luxon": "3.5.0",
@@ -68,37 +68,34 @@
68
68
  "validator": "13.12.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@babel/core": "7.24.9",
72
- "@babel/eslint-parser": "7.24.8",
73
- "@babel/preset-env": "7.24.8",
74
- "@ckeditor/jsdoc-plugins": "39.6.3",
75
- "@commitlint/config-conventional": "18.4.3",
76
- "@dwp/casa-spiderplan": "3.1.3",
77
- "@dwp/casa-spiderplan-a11y-plugin": "0.1.14",
78
- "@dwp/casa-spiderplan-zap-plugin": "0.1.10",
79
- "@dwp/eslint-config-base": "7.0.0",
71
+ "@ckeditor/jsdoc-plugins": "43.0.1",
72
+ "@commitlint/config-conventional": "19.6.0",
73
+ "@dwp/casa-spiderplan": "4.1.1",
74
+ "@dwp/casa-spiderplan-a11y-plugin": "1.0.2",
75
+ "@dwp/casa-spiderplan-zap-plugin": "1.0.2",
76
+ "@dwp/eslint-config-base": "9.0.2",
80
77
  "@types/express": "4.17.21",
81
- "@types/node": "20.14.11",
78
+ "@types/node": "22.10.2",
82
79
  "@types/nunjucks": "3.2.6",
83
- "c8": "8.0.1",
84
- "chai": "4.3.10",
85
- "cheerio": "1.0.0-rc.12",
86
- "commitlint": "18.4.3",
80
+ "c8": "10.1.3",
81
+ "chai": "5.1.2",
82
+ "cheerio": "1.0.0",
83
+ "commitlint": "19.6.1",
87
84
  "docdash": "2.0.2",
88
- "eslint": "8.57.0",
89
- "eslint-plugin-import": "2.29.1",
90
- "eslint-plugin-jsdoc": "46.9.1",
85
+ "eslint": "9.17.0",
86
+ "eslint-plugin-import": "2.31.0",
87
+ "eslint-plugin-jsdoc": "50.6.1",
91
88
  "eslint-plugin-no-unsafe-regex": "1.0.0",
92
- "eslint-plugin-security": "1.7.1",
93
- "eslint-plugin-sonarjs": "0.25.1",
94
- "fast-check": "3.20.0",
95
- "jsdoc": "4.0.3",
89
+ "eslint-plugin-security": "3.0.1",
90
+ "eslint-plugin-sonarjs": "3.0.1",
91
+ "fast-check": "3.23.2",
92
+ "jsdoc": "4.0.4",
96
93
  "jsdoc-tsimport-plugin": "1.0.5",
97
- "mocha": "10.6.0",
98
- "sass": "1.77.8",
99
- "sinon": "17.0.1",
100
- "sinon-chai": "3.7.0",
101
- "supertest": "6.3.4",
102
- "typescript": "5.5.3"
94
+ "mocha": "11.0.1",
95
+ "sass": "1.83.0",
96
+ "sinon": "19.0.2",
97
+ "sinon-chai": "4.0.0",
98
+ "supertest": "7.0.0",
99
+ "typescript": "5.7.2"
103
100
  }
104
101
  }
package/src/casa.js CHANGED
@@ -1,17 +1,17 @@
1
1
  // NOTE: Any changes made here must be reflected in `scripts/esm-wrapper.js`
2
- import configure from './lib/configure.js';
3
- import validators from './lib/validators/index.js';
4
- import field from './lib/field.js';
5
- import Plan from './lib/Plan.js';
6
- import JourneyContext from './lib/JourneyContext.js';
7
- import ValidatorFactory from './lib/ValidatorFactory.js';
8
- import ValidationError from './lib/ValidationError.js';
9
- import MutableRouter from './lib/MutableRouter.js';
10
- import waypointUrl from './lib/waypoint-url.js';
11
- import endSession from './lib/end-session.js';
12
- import * as nunjucksFilters from './lib/nunjucks-filters.js';
13
- import * as constants from './lib/constants.js';
14
- import * as contextIdGenerators from './lib/context-id-generators.js';
2
+ import configure from "./lib/configure.js";
3
+ import validators from "./lib/validators/index.js";
4
+ import field from "./lib/field.js";
5
+ import Plan from "./lib/Plan.js";
6
+ import JourneyContext from "./lib/JourneyContext.js";
7
+ import ValidatorFactory from "./lib/ValidatorFactory.js";
8
+ import ValidationError from "./lib/ValidationError.js";
9
+ import MutableRouter from "./lib/MutableRouter.js";
10
+ import waypointUrl from "./lib/waypoint-url.js";
11
+ import endSession from "./lib/end-session.js";
12
+ import * as nunjucksFilters from "./lib/nunjucks-filters.js";
13
+ import * as constants from "./lib/constants.js";
14
+ import * as contextIdGenerators from "./lib/context-id-generators.js";
15
15
 
16
16
  /** @module @dwp/govuk-casa */
17
17
  export {
@@ -1,4 +1,4 @@
1
- import { FileSystemLoader } from 'nunjucks';
1
+ import { FileSystemLoader } from "nunjucks";
2
2
 
3
3
  /**
4
4
  * @access private
@@ -11,19 +11,19 @@ import { FileSystemLoader } from 'nunjucks';
11
11
  */
12
12
 
13
13
  const VALID_BLOCKS = [
14
- 'beforeContent',
15
- 'bodyEnd',
16
- 'bodyStart',
17
- 'casaPageTitle',
18
- 'content',
19
- 'footer',
20
- 'head',
21
- 'header',
22
- 'headIcons',
23
- 'journey_form',
24
- 'main',
25
- 'pageTitle',
26
- 'skipLink',
14
+ "beforeContent",
15
+ "bodyEnd",
16
+ "bodyStart",
17
+ "casaPageTitle",
18
+ "content",
19
+ "footer",
20
+ "head",
21
+ "header",
22
+ "headIcons",
23
+ "journey_form",
24
+ "main",
25
+ "pageTitle",
26
+ "skipLink",
27
27
  ];
28
28
 
29
29
  /**
@@ -73,7 +73,9 @@ export default class CasaTemplateLoader extends FileSystemLoader {
73
73
  modifyBlock(block, modifier) {
74
74
  // Limit to only known block so the user can't do general string replacements
75
75
  if (!VALID_BLOCKS.includes(block)) {
76
- throw new Error(`Block "${String(block)}" is not a recognised template block.`);
76
+ throw new Error(
77
+ `Block "${String(block)}" is not a recognised template block.`,
78
+ );
77
79
  }
78
80
 
79
81
  this.#blockModifiers.push({
@@ -95,8 +97,10 @@ export default class CasaTemplateLoader extends FileSystemLoader {
95
97
  /* eslint-disable-next-line security/detect-object-injection */
96
98
  const { block, modifier } = this.#blockModifiers[i];
97
99
  if (source.src.indexOf(`block ${block}`) > -1) {
98
- /* eslint-disable-next-line no-param-reassign */
99
- source.src = source.src.replace(`block ${block} %}`, `block ${block} %}${modifier(name)}`);
100
+ source.src = source.src.replace(
101
+ `block ${block} %}`,
102
+ `block ${block} %}${modifier(name)}`,
103
+ );
100
104
  }
101
105
  }
102
106
  return source;
@@ -6,17 +6,15 @@
6
6
  * - Validation errors on that data
7
7
  * - Navigation information about how the user got where they are.
8
8
  */
9
- import lodash from 'lodash';
10
- import ValidationError from './ValidationError.js';
11
- import logger from './logger.js';
12
- import { notProto } from './utils.js';
13
- import { uuid as uuidGenerator } from './context-id-generators.js';
9
+ import lodash from "lodash";
10
+ import ValidationError from "./ValidationError.js";
11
+ import logger from "./logger.js";
12
+ import { notProto } from "./utils.js";
13
+ import { uuid as uuidGenerator } from "./context-id-generators.js";
14
14
 
15
- const {
16
- isPlainObject, isObject, has, isEqual,
17
- } = lodash; // CommonJS
15
+ const { isPlainObject, isObject, has, isEqual } = lodash; // CommonJS
18
16
 
19
- const log = logger('lib:journey-context');
17
+ const log = logger("lib:journey-context");
20
18
 
21
19
  const uuid = uuidGenerator();
22
20
 
@@ -50,9 +48,19 @@ const uuid = uuidGenerator();
50
48
  * @typedef {import('express').Request} ExpressRequest
51
49
  */
52
50
 
53
- export function validateObjectKey(key = '') {
51
+ /**
52
+ *
53
+ * @param {string} key Object key
54
+ * @returns {string} stringified key
55
+ * @throws {SyntaxError} for invalid keys
56
+ */
57
+ export function validateObjectKey(key = "") {
54
58
  const keyLower = String.prototype.toLowerCase.call(key);
55
- if (keyLower === 'prototype' || keyLower === '__proto__' || keyLower === 'constructor') {
59
+ if (
60
+ keyLower === "prototype" ||
61
+ keyLower === "__proto__" ||
62
+ keyLower === "constructor"
63
+ ) {
56
64
  throw new SyntaxError(`Invalid object key used, ${key}`);
57
65
  }
58
66
  return String(key);
@@ -75,17 +83,17 @@ export default class JourneyContext {
75
83
 
76
84
  #eventListenerPreState;
77
85
 
78
- static DEFAULT_CONTEXT_ID = 'default';
86
+ static DEFAULT_CONTEXT_ID = "default";
79
87
 
80
88
  /**
81
89
  * @type {symbol}
82
90
  */
83
- static ID_GENERATOR_REQ_LOG = Symbol('generatedContextIds');
91
+ static ID_GENERATOR_REQ_LOG = Symbol("generatedContextIds");
84
92
 
85
93
  /**
86
94
  * @type {symbol}
87
95
  */
88
- static ID_GENERATOR_REQ_KEY = Symbol('generateContextId');
96
+ static ID_GENERATOR_REQ_KEY = Symbol("generateContextId");
89
97
 
90
98
  /**
91
99
  * Constructor.
@@ -152,7 +160,9 @@ export default class JourneyContext {
152
160
  let dErrors = errors;
153
161
 
154
162
  if (Array.isArray(errors)) {
155
- dErrors = errors.map((e) => (e instanceof ValidationError ? e : new ValidationError(e)));
163
+ dErrors = errors.map((e) =>
164
+ e instanceof ValidationError ? e : new ValidationError(e),
165
+ );
156
166
  }
157
167
 
158
168
  deserialisedValidation[notProto(waypoint)] = dErrors;
@@ -189,13 +199,15 @@ export default class JourneyContext {
189
199
  * @throws {TypeError} When page is invalid.
190
200
  */
191
201
  getDataForPage(page) {
192
- if (typeof page === 'string') {
202
+ if (typeof page === "string") {
193
203
  return this.#data[validateObjectKey(page)];
194
204
  }
195
205
  if (isPlainObject(page)) {
196
206
  return this.#data[validateObjectKey(page.waypoint)];
197
207
  }
198
- throw new TypeError(`Page must be a string or Page object. Got ${typeof page}`);
208
+ throw new TypeError(
209
+ `Page must be a string or Page object. Got ${typeof page}`,
210
+ );
199
211
  }
200
212
 
201
213
  /**
@@ -227,12 +239,14 @@ export default class JourneyContext {
227
239
  * @throws {TypeError} When page is invalid.
228
240
  */
229
241
  setDataForPage(page, webFormData) {
230
- if (typeof page === 'string') {
242
+ if (typeof page === "string") {
231
243
  this.#data[validateObjectKey(page)] = webFormData;
232
244
  } else if (isPlainObject(page)) {
233
245
  this.#data[validateObjectKey(page.waypoint)] = webFormData;
234
246
  } else {
235
- throw new TypeError(`Page must be a string or Page object. Got ${typeof page}`)
247
+ throw new TypeError(
248
+ `Page must be a string or Page object. Got ${typeof page}`,
249
+ );
236
250
  }
237
251
 
238
252
  return this;
@@ -256,7 +270,7 @@ export default class JourneyContext {
256
270
  * @returns {JourneyContext} Chain.
257
271
  */
258
272
  removeValidationStateForPage(pageId) {
259
- /* eslint-disable-next-line no-unused-vars */
273
+ /* eslint-disable-next-line sonarjs/no-unused-vars,no-unused-vars */
260
274
  const { [pageId]: dummy, ...remaining } = this.#validation;
261
275
  this.#validation = { ...remaining };
262
276
  return this;
@@ -286,12 +300,14 @@ export default class JourneyContext {
286
300
  */
287
301
  setValidationErrorsForPage(pageId, errors = []) {
288
302
  if (!Array.isArray(errors)) {
289
- throw new SyntaxError(`Errors must be an Array. Received ${Object.prototype.toString.call(errors)}`);
303
+ throw new SyntaxError(
304
+ `Errors must be an Array. Received ${Object.prototype.toString.call(errors)}`,
305
+ );
290
306
  }
291
307
 
292
308
  errors.forEach((error) => {
293
309
  if (!(error instanceof ValidationError)) {
294
- throw new SyntaxError('Field errors must be a ValidationError');
310
+ throw new SyntaxError("Field errors must be a ValidationError");
295
311
  }
296
312
  });
297
313
 
@@ -353,7 +369,7 @@ export default class JourneyContext {
353
369
  * @param {string} language Language to set (ISO 639-1 2-letter code).
354
370
  * @returns {JourneyContext} Chain.
355
371
  */
356
- setNavigationLanguage(language = 'en') {
372
+ setNavigationLanguage(language = "en") {
357
373
  this.#nav.language = language;
358
374
  return this;
359
375
  }
@@ -376,7 +392,9 @@ export default class JourneyContext {
376
392
  purge(waypoints = []) {
377
393
  const newData = Object.create(null);
378
394
  const newValidation = Object.create(null);
379
- const toKeep = Object.keys(this.#data).filter((w) => !waypoints.includes(w));
395
+ const toKeep = Object.keys(this.#data).filter(
396
+ (w) => !waypoints.includes(w),
397
+ );
380
398
 
381
399
  // ESLint disabled as `i` is an integer
382
400
  /* eslint-disable security/detect-object-injection */
@@ -439,7 +457,9 @@ export default class JourneyContext {
439
457
  return this;
440
458
  }
441
459
 
442
- const previousContext = JourneyContext.fromObject(this.#eventListenerPreState);
460
+ const previousContext = JourneyContext.fromObject(
461
+ this.#eventListenerPreState,
462
+ );
443
463
  const listeners = this.#eventListeners.filter((l) => l.event === event);
444
464
 
445
465
  // ESLint disabled as `listeners[i]` uses an integer key, and the other keys
@@ -453,20 +473,21 @@ export default class JourneyContext {
453
473
  let runHandler = false;
454
474
 
455
475
  if (!waypoint && !field) {
456
- logMessage = 'Calling generic event handler';
476
+ logMessage = "Calling generic event handler";
457
477
  runHandler = true;
458
478
  } else if (waypoint && !field) {
459
479
  logMessage = `Calling waypoint-specific event handler on "${waypoint}"`;
460
- runHandler = previousContext.data?.[waypoint] !== undefined && !isEqual(
461
- this.data?.[waypoint],
462
- previousContext.data?.[waypoint],
463
- );
480
+ runHandler =
481
+ previousContext.data?.[waypoint] !== undefined &&
482
+ !isEqual(this.data?.[waypoint], previousContext.data?.[waypoint]);
464
483
  } else if (waypoint && field) {
465
484
  logMessage = `Calling field-specific event handler on "${waypoint} : ${field}"`;
466
- runHandler = previousContext.data?.[waypoint]?.[field] !== undefined && !isEqual(
467
- this.data?.[waypoint]?.[field],
468
- previousContext.data?.[waypoint]?.[field],
469
- );
485
+ runHandler =
486
+ previousContext.data?.[waypoint]?.[field] !== undefined &&
487
+ !isEqual(
488
+ this.data?.[waypoint]?.[field],
489
+ previousContext.data?.[waypoint]?.[field],
490
+ );
470
491
  }
471
492
 
472
493
  if (runHandler) {
@@ -514,7 +535,7 @@ export default class JourneyContext {
514
535
  */
515
536
  static fromContext(context, req) {
516
537
  if (!(context instanceof JourneyContext)) {
517
- throw new TypeError('Source context must be a JourneyContext');
538
+ throw new TypeError("Source context must be a JourneyContext");
518
539
  }
519
540
 
520
541
  const newContextObj = context.toObject();
@@ -543,15 +564,17 @@ export default class JourneyContext {
543
564
  // being remodelled as an array, we need to convert the "legacy" structure
544
565
  // into an equivalent array.
545
566
  if (isPlainObject(session?.journeyContextList)) {
546
- log.trace('Session context list already initialised as an object (legacy structure). Will convert from object to array.');
547
- /* eslint-disable-next-line no-param-reassign */
567
+ log.trace(
568
+ "Session context list already initialised as an object (legacy structure). Will convert from object to array.",
569
+ );
570
+
548
571
  session.journeyContextList = Object.entries(session.journeyContextList);
549
572
  }
550
573
 
551
574
  // Initialise new context list in the session
552
- if (!has(session, 'journeyContextList')) {
553
- log.trace('Initialising session with a default journey context list');
554
- /* eslint-disable-next-line no-param-reassign */
575
+ if (!has(session, "journeyContextList")) {
576
+ log.trace("Initialising session with a default journey context list");
577
+
555
578
  session.journeyContextList = [];
556
579
 
557
580
  const defaultContext = new JourneyContext();
@@ -575,10 +598,10 @@ export default class JourneyContext {
575
598
  return JourneyContext.DEFAULT_CONTEXT_ID;
576
599
  }
577
600
 
578
- if (typeof id !== 'string') {
579
- throw new TypeError('Context ID must be a string');
601
+ if (typeof id !== "string") {
602
+ throw new TypeError("Context ID must be a string");
580
603
  } else if (!id.match(/^[a-z0-9-]{1,64}$/)) {
581
- throw new SyntaxError('Context ID is not in the correct format');
604
+ throw new SyntaxError("Context ID is not in the correct format");
582
605
  }
583
606
 
584
607
  return id;
@@ -599,7 +622,9 @@ export default class JourneyContext {
599
622
  // Can't generate custom ID when no request object is provided, because the
600
623
  // custom generator function itself exists on that object.
601
624
  if (!req) {
602
- log.warn('Generating a context ID without a given request object. Reverting to uuid().');
625
+ log.warn(
626
+ "Generating a context ID without a given request object. Reverting to uuid().",
627
+ );
603
628
  return uuid();
604
629
  }
605
630
 
@@ -611,14 +636,18 @@ export default class JourneyContext {
611
636
  .map((c) => c.identity.id)
612
637
  .filter((id) => id !== JourneyContext.DEFAULT_CONTEXT_ID);
613
638
  const inRequestIds = req[JourneyContext.ID_GENERATOR_REQ_LOG] ?? [];
614
- const reservedIds = Array.from(new Set([...inSessionIds, ...inRequestIds]).values());
639
+ const reservedIds = Array.from(
640
+ new Set([...inSessionIds, ...inRequestIds]).values(),
641
+ );
615
642
 
616
643
  // Generate and log the ID
617
644
  const id = JourneyContext.validateContextId(
618
645
  req[JourneyContext.ID_GENERATOR_REQ_KEY].call(null, { req, reservedIds }),
619
646
  );
620
647
  if (reservedIds.includes(id)) {
621
- throw new Error(`Regenerated a context ID, ${String(id)}. It has likely not yet been used to store a new context in session using JourneyContext.putContext().`);
648
+ throw new Error(
649
+ `Regenerated a context ID, ${String(id)}. It has likely not yet been used to store a new context in session using JourneyContext.putContext().`,
650
+ );
622
651
  }
623
652
 
624
653
  if (!req[JourneyContext.ID_GENERATOR_REQ_LOG]) {
@@ -641,7 +670,10 @@ export default class JourneyContext {
641
670
  * @returns {JourneyContext} The default Journey Context
642
671
  */
643
672
  static getDefaultContext(session) {
644
- return JourneyContext.getContextById(session, JourneyContext.DEFAULT_CONTEXT_ID);
673
+ return JourneyContext.getContextById(
674
+ session,
675
+ JourneyContext.DEFAULT_CONTEXT_ID,
676
+ );
645
677
  }
646
678
 
647
679
  /**
@@ -655,7 +687,7 @@ export default class JourneyContext {
655
687
  const list = new Map(session?.journeyContextList);
656
688
  if (list.has(id)) {
657
689
  // ESLint disabled as `id` has been verified as an "own" property
658
- /* eslint-disable-next-line security/detect-object-injection */
690
+
659
691
  return JourneyContext.fromObject(list.get(id));
660
692
  }
661
693
 
@@ -672,9 +704,7 @@ export default class JourneyContext {
672
704
  static getContextByName(session, name) {
673
705
  if (session) {
674
706
  const list = new Map(session?.journeyContextList);
675
- const context = [...list.values()].find(
676
- (c) => (c.identity.name === name),
677
- );
707
+ const context = [...list.values()].find((c) => c.identity.name === name);
678
708
  if (context) {
679
709
  return JourneyContext.fromObject(context);
680
710
  }
@@ -693,9 +723,9 @@ export default class JourneyContext {
693
723
  static getContextsByTag(session, tag) {
694
724
  if (session) {
695
725
  const list = new Map(session?.journeyContextList);
696
- return [...list.values()].filter(
697
- (c) => (c.identity.tags?.includes(tag)),
698
- ).map((c) => (JourneyContext.fromObject(c)));
726
+ return [...list.values()]
727
+ .filter((c) => c.identity.tags?.includes(tag))
728
+ .map((c) => JourneyContext.fromObject(c));
699
729
  }
700
730
 
701
731
  return undefined;
@@ -708,10 +738,10 @@ export default class JourneyContext {
708
738
  * @returns {Array} Array of contexts
709
739
  */
710
740
  static getContexts(session) {
711
- if (has(session, 'journeyContextList')) {
712
- return session.journeyContextList.map(([, contextObj]) => (
713
- JourneyContext.fromObject(contextObj)
714
- ));
741
+ if (has(session, "journeyContextList")) {
742
+ return session.journeyContextList.map(([, contextObj]) =>
743
+ JourneyContext.fromObject(contextObj),
744
+ );
715
745
  }
716
746
 
717
747
  return [];
@@ -729,15 +759,15 @@ export default class JourneyContext {
729
759
  */
730
760
  static putContext(session, context, options = {}) {
731
761
  if (!isObject(session)) {
732
- throw new TypeError('Session must be an object');
762
+ throw new TypeError("Session must be an object");
733
763
  } else if (!(context instanceof JourneyContext)) {
734
- throw new TypeError('Context must be a valid JourneyContext');
764
+ throw new TypeError("Context must be a valid JourneyContext");
735
765
  } else if (context.identity.id === undefined) {
736
- throw new TypeError('Context must have an ID before storing in session');
766
+ throw new TypeError("Context must have an ID before storing in session");
737
767
  }
738
768
 
739
769
  // Initialise the session if necessary
740
- if (!has(session, 'journeyContextList')) {
770
+ if (!has(session, "journeyContextList")) {
741
771
  JourneyContext.initContextStore(session);
742
772
  }
743
773
 
@@ -745,20 +775,20 @@ export default class JourneyContext {
745
775
  const { userInfo = undefined } = options;
746
776
 
747
777
  context.applyEventListeners({
748
- event: 'waypoint-change',
778
+ event: "waypoint-change",
749
779
  session,
750
780
  userInfo,
751
781
  });
752
782
 
753
783
  context.applyEventListeners({
754
- event: 'context-change',
784
+ event: "context-change",
755
785
  session,
756
786
  userInfo,
757
787
  });
758
788
 
759
789
  const list = new Map(session.journeyContextList);
760
790
  list.set(context.identity.id, context.toObject());
761
- /* eslint-disable-next-line no-param-reassign */
791
+
762
792
  session.journeyContextList = [...list.entries()];
763
793
  }
764
794
 
@@ -783,7 +813,9 @@ export default class JourneyContext {
783
813
  * @returns {void}
784
814
  */
785
815
  static removeContextById(session, id) {
786
- const index = (session?.journeyContextList ?? []).findIndex(([contextId]) => contextId === id);
816
+ const index = (session?.journeyContextList ?? []).findIndex(
817
+ ([contextId]) => contextId === id,
818
+ );
787
819
  if (index > -1) {
788
820
  session.journeyContextList.splice(index, 1);
789
821
  }
@@ -811,8 +843,8 @@ export default class JourneyContext {
811
843
  * @returns {void}
812
844
  */
813
845
  static removeContextsByTag(session, tag) {
814
- JourneyContext.getContextsByTag(session, tag).forEach(
815
- (c) => JourneyContext.removeContext(session, c),
846
+ JourneyContext.getContextsByTag(session, tag).forEach((c) =>
847
+ JourneyContext.removeContext(session, c),
816
848
  );
817
849
  }
818
850
 
@@ -823,7 +855,9 @@ export default class JourneyContext {
823
855
  * @returns {void}
824
856
  */
825
857
  static removeContexts(session) {
826
- JourneyContext.getContexts(session).forEach((c) => JourneyContext.removeContext(session, c));
858
+ JourneyContext.getContexts(session).forEach((c) =>
859
+ JourneyContext.removeContext(session, c),
860
+ );
827
861
  }
828
862
 
829
863
  /**
@@ -840,17 +874,19 @@ export default class JourneyContext {
840
874
  JourneyContext.initContextStore(req.session);
841
875
 
842
876
  let contextId;
843
- if (has(req?.params, 'contextid')) {
844
- log.trace('Context ID found in req.params.contextid');
877
+ if (has(req?.params, "contextid")) {
878
+ log.trace("Context ID found in req.params.contextid");
845
879
  contextId = String(req.params.contextid);
846
- } else if (has(req.query, 'contextid')) {
847
- log.trace('Context ID found in req.query.contextid');
880
+ } else if (has(req.query, "contextid")) {
881
+ log.trace("Context ID found in req.query.contextid");
848
882
  contextId = String(req.query.contextid);
849
- } else if (has(req?.body, 'contextid')) {
850
- log.trace('Context ID found in req.body.contextid');
883
+ } else if (has(req?.body, "contextid")) {
884
+ log.trace("Context ID found in req.body.contextid");
851
885
  contextId = String(req.body.contextid);
852
886
  } else {
853
- log.trace('Context ID not specified or not found; will attempt to use default');
887
+ log.trace(
888
+ "Context ID not specified or not found; will attempt to use default",
889
+ );
854
890
  contextId = JourneyContext.DEFAULT_CONTEXT_ID;
855
891
  }
856
892
 
@@ -858,13 +894,16 @@ export default class JourneyContext {
858
894
  contextId = JourneyContext.validateContextId(contextId);
859
895
  const context = JourneyContext.getContextById(req.session, contextId);
860
896
  if (!context) {
861
- throw (new Error(`Could not find a context with id, ${contextId}`));
897
+ throw new Error(`Could not find a context with id, ${contextId}`);
862
898
  }
863
899
  return context;
864
900
  } catch (err) {
865
901
  log.debug(err.message);
866
- log.trace('Falling back to default context');
867
- return JourneyContext.getContextById(req.session, JourneyContext.DEFAULT_CONTEXT_ID);
902
+ log.trace("Falling back to default context");
903
+ return JourneyContext.getContextById(
904
+ req.session,
905
+ JourneyContext.DEFAULT_CONTEXT_ID,
906
+ );
868
907
  }
869
908
  }
870
909
  }