@dwp/govuk-casa 9.7.0 → 10.0.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.
- package/dist/assets/css/casa.css +1 -1
- package/dist/assets/css/casa.css.map +1 -1
- package/dist/casa.d.ts +81 -41
- package/dist/casa.d.ts.map +1 -0
- package/dist/casa.js +72 -99
- package/dist/core-plugins/edit-snapshot/src/configure.d.ts +1 -0
- package/dist/core-plugins/edit-snapshot/src/configure.d.ts.map +1 -0
- package/dist/core-plugins/edit-snapshot/src/configure.js +7 -14
- package/dist/core-plugins/edit-snapshot/src/index.d.ts +1 -0
- package/dist/core-plugins/edit-snapshot/src/index.d.ts.map +1 -0
- package/dist/core-plugins/edit-snapshot/src/index.js +3 -9
- package/dist/core-plugins/edit-snapshot/src/post-steer-hook.d.ts +2 -1
- package/dist/core-plugins/edit-snapshot/src/post-steer-hook.d.ts.map +1 -0
- package/dist/core-plugins/edit-snapshot/src/post-steer-hook.js +8 -13
- package/dist/core-plugins/edit-snapshot/src/pre-steer-hook.d.ts +2 -1
- package/dist/core-plugins/edit-snapshot/src/pre-steer-hook.d.ts.map +1 -0
- package/dist/core-plugins/edit-snapshot/src/pre-steer-hook.js +13 -18
- package/dist/core-plugins/edit-snapshot/src/utils.d.ts +8 -5
- package/dist/core-plugins/edit-snapshot/src/utils.d.ts.map +1 -0
- package/dist/core-plugins/edit-snapshot/src/utils.js +37 -19
- package/dist/core-plugins/index.d.ts +1 -0
- package/dist/core-plugins/index.d.ts.map +1 -0
- package/dist/core-plugins/index.js +1 -9
- package/dist/lib/CasaTemplateLoader.d.ts +1 -0
- package/dist/lib/CasaTemplateLoader.d.ts.map +1 -0
- package/dist/lib/CasaTemplateLoader.js +2 -6
- package/dist/lib/JourneyContext.d.ts +22 -11
- package/dist/lib/JourneyContext.d.ts.map +1 -0
- package/dist/lib/JourneyContext.js +40 -45
- package/dist/lib/MutableRouter.d.ts +74 -55
- package/dist/lib/MutableRouter.d.ts.map +1 -0
- package/dist/lib/MutableRouter.js +48 -45
- package/dist/lib/NullObject.d.ts +3 -0
- package/dist/lib/NullObject.d.ts.map +1 -0
- package/dist/lib/NullObject.js +3 -0
- package/dist/lib/Plan.d.ts +2 -1
- package/dist/lib/Plan.d.ts.map +1 -0
- package/dist/lib/Plan.js +44 -62
- package/dist/lib/ValidationError.d.ts +2 -1
- package/dist/lib/ValidationError.d.ts.map +1 -0
- package/dist/lib/ValidationError.js +3 -11
- package/dist/lib/ValidatorFactory.d.ts +5 -6
- package/dist/lib/ValidatorFactory.d.ts.map +1 -0
- package/dist/lib/ValidatorFactory.js +4 -12
- package/dist/lib/configuration-ingestor.d.ts +10 -22
- package/dist/lib/configuration-ingestor.d.ts.map +1 -0
- package/dist/lib/configuration-ingestor.js +61 -143
- package/dist/lib/configure.d.ts +2 -1
- package/dist/lib/configure.d.ts.map +1 -0
- package/dist/lib/configure.js +40 -52
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +8 -12
- package/dist/lib/context-id-generators.d.ts +1 -0
- package/dist/lib/context-id-generators.d.ts.map +1 -0
- package/dist/lib/context-id-generators.js +4 -9
- package/dist/lib/end-session.d.ts +2 -1
- package/dist/lib/end-session.d.ts.map +1 -0
- package/dist/lib/end-session.js +4 -11
- package/dist/lib/field.d.ts +2 -1
- package/dist/lib/field.d.ts.map +1 -0
- package/dist/lib/field.js +11 -21
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +13 -65
- package/dist/lib/logger.d.ts +25 -2
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +18 -9
- package/dist/lib/mount.d.ts +1 -0
- package/dist/lib/mount.d.ts.map +1 -0
- package/dist/lib/mount.js +10 -16
- package/dist/lib/nunjucks-filters.d.ts +7 -3
- package/dist/lib/nunjucks-filters.d.ts.map +1 -0
- package/dist/lib/nunjucks-filters.js +58 -71
- package/dist/lib/nunjucks.d.ts +2 -2
- package/dist/lib/nunjucks.d.ts.map +1 -0
- package/dist/lib/nunjucks.js +12 -25
- package/dist/lib/utils.d.ts +4 -2
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +14 -28
- package/dist/lib/validators/dateObject.d.ts +1 -0
- package/dist/lib/validators/dateObject.d.ts.map +1 -0
- package/dist/lib/validators/dateObject.js +14 -21
- package/dist/lib/validators/email.d.ts +1 -0
- package/dist/lib/validators/email.d.ts.map +1 -0
- package/dist/lib/validators/email.js +8 -15
- package/dist/lib/validators/inArray.d.ts +1 -0
- package/dist/lib/validators/inArray.d.ts.map +1 -0
- package/dist/lib/validators/inArray.js +8 -15
- package/dist/lib/validators/index.d.ts +1 -0
- package/dist/lib/validators/index.d.ts.map +1 -0
- package/dist/lib/validators/index.js +21 -27
- package/dist/lib/validators/nino.d.ts +1 -0
- package/dist/lib/validators/nino.d.ts.map +1 -0
- package/dist/lib/validators/nino.js +6 -13
- package/dist/lib/validators/postalAddressObject.d.ts +1 -0
- package/dist/lib/validators/postalAddressObject.d.ts.map +1 -0
- package/dist/lib/validators/postalAddressObject.js +12 -19
- package/dist/lib/validators/range.d.ts +1 -0
- package/dist/lib/validators/range.d.ts.map +1 -0
- package/dist/lib/validators/range.js +6 -13
- package/dist/lib/validators/regex.d.ts +1 -0
- package/dist/lib/validators/regex.d.ts.map +1 -0
- package/dist/lib/validators/regex.js +6 -13
- package/dist/lib/validators/required.d.ts +1 -0
- package/dist/lib/validators/required.d.ts.map +1 -0
- package/dist/lib/validators/required.js +9 -17
- package/dist/lib/validators/strlen.d.ts +1 -0
- package/dist/lib/validators/strlen.d.ts.map +1 -0
- package/dist/lib/validators/strlen.js +6 -13
- package/dist/lib/validators/wordCount.d.ts +1 -0
- package/dist/lib/validators/wordCount.d.ts.map +1 -0
- package/dist/lib/validators/wordCount.js +6 -13
- package/dist/lib/waypoint-url.d.ts +3 -2
- package/dist/lib/waypoint-url.d.ts.map +1 -0
- package/dist/lib/waypoint-url.js +12 -19
- package/dist/middleware/body-parser.d.ts +1 -0
- package/dist/middleware/body-parser.d.ts.map +1 -0
- package/dist/middleware/body-parser.js +4 -9
- package/dist/middleware/csrf.d.ts +1 -0
- package/dist/middleware/csrf.d.ts.map +1 -0
- package/dist/middleware/csrf.js +4 -8
- package/dist/middleware/data.d.ts +2 -3
- package/dist/middleware/data.d.ts.map +1 -0
- package/dist/middleware/data.js +23 -25
- package/dist/middleware/gather-fields.d.ts +3 -1
- package/dist/middleware/gather-fields.d.ts.map +1 -0
- package/dist/middleware/gather-fields.js +13 -14
- package/dist/middleware/i18n.d.ts +1 -0
- package/dist/middleware/i18n.d.ts.map +1 -0
- package/dist/middleware/i18n.js +26 -31
- package/dist/middleware/post.d.ts +1 -0
- package/dist/middleware/post.d.ts.map +1 -0
- package/dist/middleware/post.js +3 -10
- package/dist/middleware/pre.d.ts +2 -1
- package/dist/middleware/pre.d.ts.map +1 -0
- package/dist/middleware/pre.js +6 -12
- package/dist/middleware/progress-journey.d.ts +5 -3
- package/dist/middleware/progress-journey.d.ts.map +1 -0
- package/dist/middleware/progress-journey.js +20 -18
- package/dist/middleware/sanitise-fields.d.ts +5 -3
- package/dist/middleware/sanitise-fields.d.ts.map +1 -0
- package/dist/middleware/sanitise-fields.js +25 -17
- package/dist/middleware/serve-first-waypoint.d.ts +1 -0
- package/dist/middleware/serve-first-waypoint.d.ts.map +1 -0
- package/dist/middleware/serve-first-waypoint.js +3 -6
- package/dist/middleware/session.d.ts +15 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +53 -57
- package/dist/middleware/skip-waypoint.d.ts +3 -2
- package/dist/middleware/skip-waypoint.d.ts.map +1 -0
- package/dist/middleware/skip-waypoint.js +15 -14
- package/dist/middleware/steer-journey.d.ts +2 -1
- package/dist/middleware/steer-journey.d.ts.map +1 -0
- package/dist/middleware/steer-journey.js +7 -13
- package/dist/middleware/strip-proxy-path.d.ts +3 -2
- package/dist/middleware/strip-proxy-path.d.ts.map +1 -0
- package/dist/middleware/strip-proxy-path.js +24 -24
- package/dist/middleware/validate-fields.d.ts +7 -4
- package/dist/middleware/validate-fields.d.ts.map +1 -0
- package/dist/middleware/validate-fields.js +22 -11
- package/dist/routes/ancillary.d.ts +1 -0
- package/dist/routes/ancillary.d.ts.map +1 -0
- package/dist/routes/ancillary.js +3 -10
- package/dist/routes/journey.d.ts +7 -2
- package/dist/routes/journey.d.ts.map +1 -0
- package/dist/routes/journey.js +56 -55
- package/dist/routes/static.d.ts +1 -0
- package/dist/routes/static.d.ts.map +1 -0
- package/dist/routes/static.js +15 -23
- package/package.json +20 -26
- package/src/casa.js +49 -29
- package/src/core-plugins/edit-snapshot/src/post-steer-hook.js +1 -0
- package/src/core-plugins/edit-snapshot/src/pre-steer-hook.js +2 -1
- package/src/core-plugins/edit-snapshot/src/utils.js +29 -1
- package/src/lib/JourneyContext.js +31 -28
- package/src/lib/MutableRouter.js +47 -38
- package/src/lib/NullObject.js +4 -0
- package/src/lib/Plan.js +41 -55
- package/src/lib/ValidationError.js +2 -4
- package/src/lib/ValidatorFactory.js +3 -5
- package/src/lib/configuration-ingestor.js +18 -38
- package/src/lib/configure.js +7 -10
- package/src/lib/end-session.js +1 -1
- package/src/lib/field.js +7 -12
- package/src/lib/logger.js +16 -0
- package/src/lib/mount.js +1 -1
- package/src/lib/nunjucks-filters.js +51 -61
- package/src/lib/nunjucks.js +3 -12
- package/src/lib/utils.js +2 -1
- package/src/lib/validators/dateObject.js +3 -4
- package/src/lib/validators/postalAddressObject.js +6 -7
- package/src/lib/validators/required.js +1 -3
- package/src/lib/waypoint-url.js +15 -19
- package/src/middleware/csrf.js +1 -1
- package/src/middleware/data.js +13 -13
- package/src/middleware/gather-fields.js +8 -2
- package/src/middleware/i18n.js +9 -6
- package/src/middleware/pre.js +1 -1
- package/src/middleware/progress-journey.js +8 -0
- package/src/middleware/sanitise-fields.js +17 -2
- package/src/middleware/session.js +53 -12
- package/src/middleware/skip-waypoint.js +8 -1
- package/src/middleware/steer-journey.js +1 -1
- package/src/middleware/strip-proxy-path.js +21 -16
- package/src/middleware/validate-fields.js +19 -0
- package/src/routes/journey.js +18 -8
- package/src/routes/static.js +5 -4
- package/views/casa/layouts/journey.njk +1 -1
- package/views/casa/layouts/main.njk +11 -21
- package/dist/casa.js.map +0 -1
- package/dist/core-plugins/edit-snapshot/src/configure.js.map +0 -1
- package/dist/core-plugins/edit-snapshot/src/index.js.map +0 -1
- package/dist/core-plugins/edit-snapshot/src/post-steer-hook.js.map +0 -1
- package/dist/core-plugins/edit-snapshot/src/pre-steer-hook.js.map +0 -1
- package/dist/core-plugins/edit-snapshot/src/utils.js.map +0 -1
- package/dist/core-plugins/index.js.map +0 -1
- package/dist/lib/CasaTemplateLoader.js.map +0 -1
- package/dist/lib/JourneyContext.js.map +0 -1
- package/dist/lib/MutableRouter.js.map +0 -1
- package/dist/lib/Plan.js.map +0 -1
- package/dist/lib/ValidationError.js.map +0 -1
- package/dist/lib/ValidatorFactory.js.map +0 -1
- package/dist/lib/configuration-ingestor.js.map +0 -1
- package/dist/lib/configure.js.map +0 -1
- package/dist/lib/constants.js.map +0 -1
- package/dist/lib/context-id-generators.js.map +0 -1
- package/dist/lib/dirname.cjs +0 -1
- package/dist/lib/dirname.d.cts +0 -2
- package/dist/lib/end-session.js.map +0 -1
- package/dist/lib/field.js.map +0 -1
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/logger.js.map +0 -1
- package/dist/lib/mount.js.map +0 -1
- package/dist/lib/nunjucks-filters.js.map +0 -1
- package/dist/lib/nunjucks.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
- package/dist/lib/validators/dateObject.js.map +0 -1
- package/dist/lib/validators/email.js.map +0 -1
- package/dist/lib/validators/inArray.js.map +0 -1
- package/dist/lib/validators/index.js.map +0 -1
- package/dist/lib/validators/nino.js.map +0 -1
- package/dist/lib/validators/postalAddressObject.js.map +0 -1
- package/dist/lib/validators/range.js.map +0 -1
- package/dist/lib/validators/regex.js.map +0 -1
- package/dist/lib/validators/required.js.map +0 -1
- package/dist/lib/validators/strlen.js.map +0 -1
- package/dist/lib/validators/wordCount.js.map +0 -1
- package/dist/lib/waypoint-url.js.map +0 -1
- package/dist/middleware/body-parser.js.map +0 -1
- package/dist/middleware/csrf.js.map +0 -1
- package/dist/middleware/data.js.map +0 -1
- package/dist/middleware/dirname.cjs +0 -1
- package/dist/middleware/dirname.d.cts +0 -2
- package/dist/middleware/gather-fields.js.map +0 -1
- package/dist/middleware/i18n.js.map +0 -1
- package/dist/middleware/post.js.map +0 -1
- package/dist/middleware/pre.js.map +0 -1
- package/dist/middleware/progress-journey.js.map +0 -1
- package/dist/middleware/sanitise-fields.js.map +0 -1
- package/dist/middleware/serve-first-waypoint.js.map +0 -1
- package/dist/middleware/session.js.map +0 -1
- package/dist/middleware/skip-waypoint.js.map +0 -1
- package/dist/middleware/steer-journey.js.map +0 -1
- package/dist/middleware/strip-proxy-path.js.map +0 -1
- package/dist/middleware/validate-fields.js.map +0 -1
- package/dist/mjs/esm-wrapper.js +0 -20
- package/dist/mjs/package.json +0 -3
- package/dist/package.json +0 -3
- package/dist/routes/ancillary.js.map +0 -1
- package/dist/routes/dirname.cjs +0 -1
- package/dist/routes/dirname.d.cts +0 -2
- package/dist/routes/journey.js.map +0 -1
- package/dist/routes/static.js.map +0 -1
- package/src/lib/dirname.cjs +0 -1
- package/src/middleware/dirname.cjs +0 -1
- package/src/routes/dirname.cjs +0 -1
|
@@ -1,82 +1,72 @@
|
|
|
1
|
-
import
|
|
1
|
+
import deepmerge from "@fastify/deepmerge";
|
|
2
2
|
import { DateTime } from "luxon";
|
|
3
3
|
import nunjucks from "nunjucks";
|
|
4
|
+
import isPlainObject from "is-plain-obj";
|
|
5
|
+
import NullObject from "./NullObject.js";
|
|
4
6
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @param {any} o Value to test
|
|
36
|
-
* @returns {boolean} True if an object
|
|
37
|
-
*/
|
|
38
|
-
function isObject(o) {
|
|
39
|
-
return Object.prototype.toString.call(o) === "[object Object]";
|
|
40
|
-
}
|
|
7
|
+
const merge = deepmerge({
|
|
8
|
+
all: true,
|
|
9
|
+
onlyDefinedProperties: true,
|
|
10
|
+
isMergeableObject: isMergable,
|
|
11
|
+
mergeArray(options) {
|
|
12
|
+
const deepmerge = options.deepmerge;
|
|
13
|
+
const clone = options.clone;
|
|
14
|
+
return function (target, source) {
|
|
15
|
+
let i = 0;
|
|
16
|
+
const tl = target.length;
|
|
17
|
+
const sl = source.length;
|
|
18
|
+
const il = Math.max(tl, sl);
|
|
19
|
+
const result = new Array(il);
|
|
20
|
+
/* eslint-disable security/detect-object-injection */
|
|
21
|
+
for (i = 0; i < il; ++i) {
|
|
22
|
+
const targetItem = target[i];
|
|
23
|
+
const sourceItem = source[i];
|
|
24
|
+
if (i < sl) {
|
|
25
|
+
result[i] = deepmerge(targetItem, sourceItem);
|
|
26
|
+
} else {
|
|
27
|
+
result[i] = clone(targetItem);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/* eslint-enable security/detect-object-injection */
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
41
35
|
|
|
42
36
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
37
|
+
* Returns true if object is mergable (plain object or Array)
|
|
38
|
+
*
|
|
39
|
+
* @param {object} object Input object
|
|
40
|
+
* @returns {boolean} Is mergable
|
|
45
41
|
*/
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
if (isObject(o) === false) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
const ctor = o.constructor;
|
|
54
|
-
if (ctor === undefined) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
const prot = ctor.prototype;
|
|
58
|
-
if (isObject(prot) === false) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
return Object.hasOwn(prot, "isPrototypeOf");
|
|
42
|
+
function isMergable(object) {
|
|
43
|
+
return Array.isArray(object) || isPlainObject(object);
|
|
62
44
|
}
|
|
63
45
|
|
|
64
46
|
/**
|
|
65
|
-
*
|
|
47
|
+
* Merge multiple objects into one object
|
|
48
|
+
*
|
|
49
|
+
* @memberof NunjucksFilters
|
|
50
|
+
* @param {...(object | Array)} objects Objects to merge
|
|
66
51
|
* @returns {object} Merged object
|
|
67
52
|
*/
|
|
68
53
|
function mergeObjects(...objects) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
const merged = merge(new NullObject(), ...objects);
|
|
55
|
+
if (merged === null) {
|
|
56
|
+
for (const object of objects) {
|
|
57
|
+
if (!isMergable(object)) {
|
|
58
|
+
throw new TypeError(`Cannot convert ${typeof object} to object`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return merged;
|
|
73
63
|
}
|
|
74
64
|
|
|
75
65
|
/**
|
|
76
66
|
* Determine whether a value exists in a list.
|
|
77
67
|
*
|
|
78
68
|
* @memberof NunjucksFilters
|
|
79
|
-
* @param {
|
|
69
|
+
* @param {Array} source List of items to search
|
|
80
70
|
* @param {any} search Item to search within the `source`
|
|
81
71
|
* @returns {boolean} True if the search item was found
|
|
82
72
|
*/
|
package/src/lib/nunjucks.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
1
|
import { Environment } from "nunjucks";
|
|
4
|
-
import
|
|
2
|
+
import packageInfo from "../../package.json" with { type: "json" };
|
|
5
3
|
import CasaTemplateLoader from "./CasaTemplateLoader.js";
|
|
6
4
|
import {
|
|
7
5
|
mergeObjects,
|
|
@@ -20,11 +18,10 @@ import {
|
|
|
20
18
|
* Create a Nunjucks environment.
|
|
21
19
|
*
|
|
22
20
|
* @param {NunjucksOptions} options Nunjucks options
|
|
23
|
-
* @param {boolean} govukRebrand GovukRebrand flag
|
|
24
21
|
* @returns {Environment} Nunjucks Environment instance
|
|
25
22
|
* @access private
|
|
26
23
|
*/
|
|
27
|
-
export default function nunjucksConfig({ views = []
|
|
24
|
+
export default function nunjucksConfig({ views = [] }) {
|
|
28
25
|
// Prepare a single Nunjucks environment for all responses to use. Note that
|
|
29
26
|
// we cannot prepare response-specific global functions/filters if we use a
|
|
30
27
|
// single environment, but the performance gains of doing so are significant.
|
|
@@ -45,13 +42,7 @@ export default function nunjucksConfig({ views = [], govukRebrand }) {
|
|
|
45
42
|
|
|
46
43
|
// Globals
|
|
47
44
|
// These can't be modified once set. But they can be overridden by res.locals.
|
|
48
|
-
env.addGlobal(
|
|
49
|
-
"casaVersion",
|
|
50
|
-
/* eslint-disable-next-line security/detect-non-literal-fs-filename */
|
|
51
|
-
JSON.parse(readFileSync(resolve(dirname, "../../package.json"))).version,
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
env.addGlobal("govukRebrand", govukRebrand);
|
|
45
|
+
env.addGlobal("casaVersion", packageInfo.version);
|
|
55
46
|
env.addGlobal("mergeObjects", mergeObjects);
|
|
56
47
|
env.addGlobal("includes", includes);
|
|
57
48
|
env.addGlobal("formatDateObject", formatDateObject);
|
package/src/lib/utils.js
CHANGED
|
@@ -44,7 +44,8 @@ export function isStringable(value) {
|
|
|
44
44
|
* @param {string} hookName Hook name (including scope prefix)
|
|
45
45
|
* @param {string} path URL path to match (relative to mountUrl)
|
|
46
46
|
* @param {Hook[]} hooks Hooks to be applied at the page level
|
|
47
|
-
* @returns {
|
|
47
|
+
* @returns {import("express").RequestHandler[]} An array of middleware that
|
|
48
|
+
* should be applied
|
|
48
49
|
* @access private
|
|
49
50
|
*/
|
|
50
51
|
export function resolveMiddlewareHooks(hookName, path, hooks = []) {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import isPlainObject from "is-plain-obj";
|
|
1
2
|
import { DateTime } from "luxon";
|
|
2
|
-
import
|
|
3
|
+
import NullObject from "../NullObject.js";
|
|
3
4
|
import ValidationError from "../ValidationError.js";
|
|
4
5
|
import ValidatorFactory from "../ValidatorFactory.js";
|
|
5
6
|
import { stringifyInput, stripWhitespace } from "../utils.js";
|
|
6
7
|
|
|
7
|
-
const { isPlainObject } = lodash;
|
|
8
|
-
|
|
9
8
|
/**
|
|
10
9
|
* @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
|
|
11
10
|
* @access private
|
|
@@ -172,7 +171,7 @@ export default class DateObject extends ValidatorFactory {
|
|
|
172
171
|
mm: stripWhitespace(stringifyInput(value.mm)),
|
|
173
172
|
yyyy: stripWhitespace(stringifyInput(value.yyyy)),
|
|
174
173
|
}
|
|
175
|
-
:
|
|
174
|
+
: new NullObject();
|
|
176
175
|
}
|
|
177
176
|
return undefined;
|
|
178
177
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isPlainObject from "is-plain-obj";
|
|
2
|
+
import NullObject from "../NullObject.js";
|
|
2
3
|
import ValidationError from "../ValidationError.js";
|
|
3
4
|
import ValidatorFactory from "../ValidatorFactory.js";
|
|
4
5
|
import { stringifyInput } from "../utils.js";
|
|
5
6
|
|
|
6
|
-
const { isPlainObject } = lodash; // CommonjS
|
|
7
|
-
|
|
8
7
|
/**
|
|
9
8
|
* @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
|
|
10
9
|
* @access private
|
|
@@ -91,7 +90,7 @@ export default class PostalAddressObject extends ValidatorFactory {
|
|
|
91
90
|
: err;
|
|
92
91
|
|
|
93
92
|
// Work out required/optional parts based on config
|
|
94
|
-
const reqF =
|
|
93
|
+
const reqF = new NullObject();
|
|
95
94
|
const reqC = cfg.requiredFields;
|
|
96
95
|
reqF.address1 = reqC.indexOf("address1") > -1;
|
|
97
96
|
reqF.address2 = reqC.indexOf("address2") > -1;
|
|
@@ -140,7 +139,7 @@ export default class PostalAddressObject extends ValidatorFactory {
|
|
|
140
139
|
if (condMissingOrRegexMismatch || condExceedStrlen) {
|
|
141
140
|
valid = false;
|
|
142
141
|
errorMsgs.push(
|
|
143
|
-
Object.assign(
|
|
142
|
+
Object.assign(new NullObject(), objectifyError(attr[3]), {
|
|
144
143
|
fieldKeySuffix: `[${k}]`,
|
|
145
144
|
}),
|
|
146
145
|
);
|
|
@@ -163,7 +162,7 @@ export default class PostalAddressObject extends ValidatorFactory {
|
|
|
163
162
|
sanitise(value) {
|
|
164
163
|
// Only objects are supported
|
|
165
164
|
if (!isPlainObject(value)) {
|
|
166
|
-
return
|
|
165
|
+
return new NullObject();
|
|
167
166
|
}
|
|
168
167
|
|
|
169
168
|
// Prune unrecognised attributes, and coerce to Strings
|
|
@@ -179,6 +178,6 @@ export default class PostalAddressObject extends ValidatorFactory {
|
|
|
179
178
|
.filter(([k]) => validKeys.includes(k))
|
|
180
179
|
.map(([k, v]) => [k, stringifyInput(v)]),
|
|
181
180
|
);
|
|
182
|
-
return Object.assign(
|
|
181
|
+
return Object.assign(new NullObject(), pruned);
|
|
183
182
|
}
|
|
184
183
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isPlainObject from "is-plain-obj";
|
|
2
2
|
import { isEmpty, isStringable, stringifyInput } from "../utils.js";
|
|
3
3
|
import ValidatorFactory from "../ValidatorFactory.js";
|
|
4
4
|
import ValidationError from "../ValidationError.js";
|
|
5
5
|
|
|
6
|
-
const { isPlainObject } = lodash; // CommonJS
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
|
|
10
8
|
* @access private
|
package/src/lib/waypoint-url.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import NullObject from "./NullObject.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @typedef {import("./index").JourneyContext} JourneyContext
|
|
3
5
|
* @access private
|
|
@@ -14,7 +16,7 @@ const reUrlProtocolExtract = /^url:\/\/(.+)$/i;
|
|
|
14
16
|
* @access private
|
|
15
17
|
*/
|
|
16
18
|
const sanitiseWaypoint = (w) =>
|
|
17
|
-
w.replace(/[^/a-z0-9_-]
|
|
19
|
+
w.replace(/[^/a-z0-9_-]+/gi, "").replace(/\/+/g, "/");
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Sanitise a waypoint string, with allowed URL parameters: contextid =
|
|
@@ -25,32 +27,26 @@ const sanitiseWaypoint = (w) =>
|
|
|
25
27
|
* @access private
|
|
26
28
|
*/
|
|
27
29
|
const sanitiseWaypointWithAllowedParams = (w) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (parts.length !== 2) {
|
|
30
|
+
const queryIndex = w.indexOf("?");
|
|
31
|
+
if (queryIndex === -1 || queryIndex !== w.lastIndexOf("?")) {
|
|
31
32
|
return sanitiseWaypoint(w);
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
validatedUrlSearchParams.set(pk, urlSearchParams.get(pk));
|
|
41
|
-
}
|
|
34
|
+
|
|
35
|
+
const waypoint = w.substring(0, queryIndex);
|
|
36
|
+
const urlSearchParams = new URLSearchParams(w.substring(queryIndex + 1));
|
|
37
|
+
|
|
38
|
+
let query = "";
|
|
39
|
+
if (urlSearchParams.has("contextid")) {
|
|
40
|
+
query += `?contextid=${encodeURIComponent(urlSearchParams.get("contextid"))}`;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
return `${sanitiseWaypoint(waypoint)}
|
|
45
|
-
/\?$/,
|
|
46
|
-
"",
|
|
47
|
-
);
|
|
43
|
+
return `${sanitiseWaypoint(waypoint)}${query}`;
|
|
48
44
|
};
|
|
49
45
|
|
|
50
46
|
/**
|
|
51
47
|
* Generate a URL pointing at a particular waypoint.
|
|
52
48
|
*
|
|
53
|
-
* @memberof module
|
|
49
|
+
* @memberof module:"@dwp/govuk-casa"
|
|
54
50
|
* @example
|
|
55
51
|
* // generates: /path/details?edit&editorigin=%2Fsomewhere%2Felse
|
|
56
52
|
* waypointUrl({
|
|
@@ -80,7 +76,7 @@ export default function waypointUrl(
|
|
|
80
76
|
editOrigin,
|
|
81
77
|
skipTo,
|
|
82
78
|
routeName = "next",
|
|
83
|
-
} =
|
|
79
|
+
} = new NullObject(),
|
|
84
80
|
) {
|
|
85
81
|
const url = new URL("https://placeholder.test");
|
|
86
82
|
|
package/src/middleware/csrf.js
CHANGED
|
@@ -16,7 +16,7 @@ import { csrfSync } from "csrf-sync";
|
|
|
16
16
|
*/
|
|
17
17
|
export default function csrfMiddleware() {
|
|
18
18
|
const { csrfSynchronisedProtection } = csrfSync({
|
|
19
|
-
getTokenFromRequest: (req) => req.body
|
|
19
|
+
getTokenFromRequest: (req) => req.body?._csrf,
|
|
20
20
|
});
|
|
21
21
|
return [
|
|
22
22
|
csrfSynchronisedProtection,
|
package/src/middleware/data.js
CHANGED
|
@@ -22,8 +22,14 @@ import waypointUrl from "../lib/waypoint-url.js";
|
|
|
22
22
|
* @access private
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Get edit orgin
|
|
27
|
+
*
|
|
28
|
+
* @param {import("express").Request} req Express request
|
|
29
|
+
* @returns {string} Currently set edit origin
|
|
30
|
+
*/
|
|
25
31
|
const editOrigin = (req) => {
|
|
26
|
-
if (Object.hasOwn(req.query, "editorigin")) {
|
|
32
|
+
if (req.query && Object.hasOwn(req.query, "editorigin")) {
|
|
27
33
|
return waypointUrl({ waypoint: req.query.editorigin });
|
|
28
34
|
}
|
|
29
35
|
if (req.body && Object.hasOwn(req.body, "editorigin")) {
|
|
@@ -43,16 +49,9 @@ const editOrigin = (req) => {
|
|
|
43
49
|
* @param {Plan} opts.plan CASA Plan
|
|
44
50
|
* @param {ContextEventHandler[]} opts.events Event handlers
|
|
45
51
|
* @param {ContextIdGenerator} opts.contextIdGenerator Content ID generator
|
|
46
|
-
* @param {boolean} ops.govukRebrand Govuk rebrand feature flag
|
|
47
|
-
* @param opts.govukRebrand
|
|
48
52
|
* @returns {RequestHandler[]} Middleware functions
|
|
49
53
|
*/
|
|
50
|
-
export default function dataMiddleware({
|
|
51
|
-
plan,
|
|
52
|
-
events,
|
|
53
|
-
contextIdGenerator,
|
|
54
|
-
govukRebrand,
|
|
55
|
-
}) {
|
|
54
|
+
export default function dataMiddleware({ plan, events, contextIdGenerator }) {
|
|
56
55
|
return [
|
|
57
56
|
(req, res, next) => {
|
|
58
57
|
/* ------------------------------------------------ Request decorations */
|
|
@@ -73,9 +72,11 @@ export default function dataMiddleware({
|
|
|
73
72
|
|
|
74
73
|
// Edit mode
|
|
75
74
|
editMode:
|
|
76
|
-
(
|
|
75
|
+
(req.query &&
|
|
76
|
+
Object.hasOwn(req.query, "edit") &&
|
|
77
77
|
Object.hasOwn(req.query, "editorigin")) ||
|
|
78
|
-
(
|
|
78
|
+
(req.body &&
|
|
79
|
+
Object.hasOwn(req.body, "edit") &&
|
|
79
80
|
Object.hasOwn(req.body, "editorigin")),
|
|
80
81
|
editOrigin: editOrigin(req),
|
|
81
82
|
};
|
|
@@ -131,8 +132,7 @@ export default function dataMiddleware({
|
|
|
131
132
|
// htmlLang = req.language is provided by i18n-http-middleware
|
|
132
133
|
// assetPath = used for linking to static assets in the govuk-frontend module
|
|
133
134
|
res.locals.htmlLang = req.language;
|
|
134
|
-
|
|
135
|
-
res.locals.assetPath = `${staticMountUrl}govuk/assets${rebrandAssetPath}`;
|
|
135
|
+
res.locals.assetPath = `${staticMountUrl}govuk/assets`;
|
|
136
136
|
|
|
137
137
|
// Function for building URLs. This will be curried with the `mountUrl`,
|
|
138
138
|
// `journeyContext`, `edit` and `editOrigin` for convenience. This means
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// - Remove validation date of JourneyContext so it can re-evaluted
|
|
5
5
|
|
|
6
6
|
import JourneyContext from "../lib/JourneyContext.js";
|
|
7
|
+
import NullObject from "../lib/NullObject.js";
|
|
7
8
|
import { REQUEST_PHASE_GATHER } from "../lib/constants.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -11,6 +12,11 @@ import { REQUEST_PHASE_GATHER } from "../lib/constants.js";
|
|
|
11
12
|
* @access private
|
|
12
13
|
*/
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {import("express").RequestHandler} RequestHandler
|
|
17
|
+
* @access private
|
|
18
|
+
*/
|
|
19
|
+
|
|
14
20
|
/**
|
|
15
21
|
* Gather the field data from `req.body` into the current JourneyContext
|
|
16
22
|
*
|
|
@@ -21,7 +27,7 @@ import { REQUEST_PHASE_GATHER } from "../lib/constants.js";
|
|
|
21
27
|
* @param {object} obj Options
|
|
22
28
|
* @param {string} obj.waypoint Waypoint
|
|
23
29
|
* @param {PageField[]} [obj.fields] Fields. Default is `[]`
|
|
24
|
-
* @returns {
|
|
30
|
+
* @returns {RequestHandler[]} Array of middleware
|
|
25
31
|
*/
|
|
26
32
|
export default ({ waypoint, fields = [] }) => [
|
|
27
33
|
(req, res, next) => {
|
|
@@ -35,7 +41,7 @@ export default ({ waypoint, fields = [] }) => [
|
|
|
35
41
|
// Ignore data for any non-persistent fields
|
|
36
42
|
// ESLint disabled as `fields`, `i` and `name` are dev-controlled
|
|
37
43
|
/* eslint-disable security/detect-object-injection */
|
|
38
|
-
const persistentBody =
|
|
44
|
+
const persistentBody = new NullObject();
|
|
39
45
|
for (let i = 0, l = fields.length; i < l; i++) {
|
|
40
46
|
if (
|
|
41
47
|
fields[i].meta.persist &&
|
package/src/middleware/i18n.js
CHANGED
|
@@ -2,9 +2,10 @@ import { createInstance } from "i18next";
|
|
|
2
2
|
import { LanguageDetector, handle } from "i18next-http-middleware";
|
|
3
3
|
import { resolve, basename } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
|
-
import deepmerge from "deepmerge";
|
|
5
|
+
import deepmerge from "@fastify/deepmerge";
|
|
6
6
|
import { load as jsYamlLoad } from "js-yaml";
|
|
7
7
|
import logger from "../lib/logger.js";
|
|
8
|
+
import NullObject from "../lib/NullObject.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @typedef {import("express").RequestHandler} RequestHandler
|
|
@@ -13,6 +14,8 @@ import logger from "../lib/logger.js";
|
|
|
13
14
|
|
|
14
15
|
const log = logger("middleware:i18n");
|
|
15
16
|
|
|
17
|
+
const merge = deepmerge({ onlyDefinedProperties: true });
|
|
18
|
+
|
|
16
19
|
const loadJson = (file) => {
|
|
17
20
|
// Strip out newlines (this is a legacy feature which we're keeping for
|
|
18
21
|
// backwards compatibility).
|
|
@@ -35,13 +38,13 @@ const extract = (file) => {
|
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
const loadResources = (languages, directories) => {
|
|
38
|
-
const store =
|
|
41
|
+
const store = new NullObject();
|
|
39
42
|
|
|
40
43
|
for (const language of languages) {
|
|
41
44
|
// ESLint disabled as `store`, `language` and `ns` are all dev-controlled,
|
|
42
45
|
// and this function is only called once, at boot-time.
|
|
43
46
|
/* eslint-disable security/detect-object-injection */
|
|
44
|
-
store[language] =
|
|
47
|
+
store[language] = new NullObject();
|
|
45
48
|
|
|
46
49
|
for (const basedir of directories) {
|
|
47
50
|
const dir = resolve(basedir, language);
|
|
@@ -56,10 +59,10 @@ const loadResources = (languages, directories) => {
|
|
|
56
59
|
const { ns, data } = extract(resolve(dir, file));
|
|
57
60
|
|
|
58
61
|
if (store[language][ns] === undefined) {
|
|
59
|
-
store[language][ns] =
|
|
62
|
+
store[language][ns] = new NullObject();
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
store[language][ns] =
|
|
65
|
+
store[language][ns] = merge(store[language][ns], data);
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
/* eslint-enable security/detect-object-injection */
|
|
@@ -115,7 +118,7 @@ export default function i18nMiddleware({
|
|
|
115
118
|
if (!req.session.language) {
|
|
116
119
|
req.session.language = languages[0];
|
|
117
120
|
}
|
|
118
|
-
if (req?.
|
|
121
|
+
if (req.query?.lang && languages.includes(req.query.lang)) {
|
|
119
122
|
req.session.language = String(req.query.lang);
|
|
120
123
|
}
|
|
121
124
|
next();
|
package/src/middleware/pre.js
CHANGED
|
@@ -33,7 +33,7 @@ function casaCspNonce(req, res) {
|
|
|
33
33
|
* @param {object} opts Options
|
|
34
34
|
* @param {HelmetConfigurator} opts.helmetConfigurator Function to customise
|
|
35
35
|
* Helmet configuration
|
|
36
|
-
* @returns {
|
|
36
|
+
* @returns {import("express").RequestHandler[]} List of middleware
|
|
37
37
|
*/
|
|
38
38
|
export default ({ helmetConfigurator = (config) => config } = {}) => [
|
|
39
39
|
// Only allow certain request methods
|
|
@@ -25,6 +25,14 @@ const saveAndRedirect = (session, journeyContext, url, res, next) => {
|
|
|
25
25
|
});
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Get "progress journey" middleware for a given waypoint
|
|
30
|
+
*
|
|
31
|
+
* @param {object} opts Options
|
|
32
|
+
* @param {string} opts.waypoint Waypoint
|
|
33
|
+
* @param {Plan} opts.plan CASA Plan
|
|
34
|
+
* @returns {import("express").RequestHandler[]} Middleware functions
|
|
35
|
+
*/
|
|
28
36
|
export default ({ waypoint, plan }) => [
|
|
29
37
|
(req, res, next) => {
|
|
30
38
|
// Determine the next available waypoint after the current one
|
|
@@ -4,7 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import fieldFactory from "../lib/field.js";
|
|
6
6
|
import JourneyContext from "../lib/JourneyContext.js";
|
|
7
|
+
import NullObject from "../lib/NullObject.js";
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Get "sanitise fields" middleware for a given waypoint
|
|
11
|
+
*
|
|
12
|
+
* @param {object} opts Options
|
|
13
|
+
* @param {string} opts.waypoint Waypoint
|
|
14
|
+
* @param {PageField[]} opts.fields Fields to sanitise
|
|
15
|
+
* @returns {import("express").RequestHandler[]} Middleware functions
|
|
16
|
+
*/
|
|
8
17
|
export default ({ waypoint, fields = [] }) => {
|
|
9
18
|
// Add some common, transient fields to ensure they survive beyond this sanitisation process
|
|
10
19
|
fields.push(
|
|
@@ -35,9 +44,10 @@ export default ({ waypoint, fields = [] }) => {
|
|
|
35
44
|
// those that do not have an entry in `fields`)
|
|
36
45
|
// EsLint disabled as `fields`, `i` & `name` are only controlled by dev
|
|
37
46
|
/* eslint-disable security/detect-object-injection */
|
|
38
|
-
const prunedBody =
|
|
47
|
+
const prunedBody = new NullObject();
|
|
39
48
|
for (let i = 0, l = fields.length; i < l; i++) {
|
|
40
49
|
if (
|
|
50
|
+
req.body &&
|
|
41
51
|
Object.hasOwn(req.body, fields[i].name) &&
|
|
42
52
|
req.body[fields[i].name] !== undefined
|
|
43
53
|
) {
|
|
@@ -54,7 +64,7 @@ export default ({ waypoint, fields = [] }) => {
|
|
|
54
64
|
|
|
55
65
|
// Second, prune any fields that do not pass the validation conditional,
|
|
56
66
|
// and process those that do.
|
|
57
|
-
const sanitisedBody =
|
|
67
|
+
const sanitisedBody = new NullObject();
|
|
58
68
|
for (let i = 0, l = fields.length; i < l; i++) {
|
|
59
69
|
const field =
|
|
60
70
|
fields[i]; /* eslint-disable-line security/detect-object-injection */
|
|
@@ -78,3 +88,8 @@ export default ({ waypoint, fields = [] }) => {
|
|
|
78
88
|
},
|
|
79
89
|
];
|
|
80
90
|
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @typedef {import("../casa").PageField} PageField
|
|
94
|
+
* @access private
|
|
95
|
+
*/
|