@dwp/govuk-casa 8.15.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/assets/css/casa.css +2 -1
- package/dist/assets/css/casa.css.map +1 -0
- package/dist/casa.d.ts +122 -99
- package/dist/casa.js +120 -88
- package/dist/casa.js.map +1 -1
- package/dist/lib/CasaTemplateLoader.d.ts +4 -4
- package/dist/lib/CasaTemplateLoader.js +16 -16
- package/dist/lib/CasaTemplateLoader.js.map +1 -1
- package/dist/lib/JourneyContext.d.ts +38 -40
- package/dist/lib/JourneyContext.js +89 -75
- package/dist/lib/JourneyContext.js.map +1 -1
- package/dist/lib/MutableRouter.d.ts +40 -41
- package/dist/lib/MutableRouter.js +64 -71
- package/dist/lib/MutableRouter.js.map +1 -1
- package/dist/lib/Plan.d.ts +29 -26
- package/dist/lib/Plan.js +85 -71
- package/dist/lib/Plan.js.map +1 -1
- package/dist/lib/ValidationError.d.ts +16 -15
- package/dist/lib/ValidationError.js +21 -20
- package/dist/lib/ValidationError.js.map +1 -1
- package/dist/lib/ValidatorFactory.d.ts +15 -13
- package/dist/lib/ValidatorFactory.js +14 -12
- package/dist/lib/ValidatorFactory.js.map +1 -1
- package/dist/lib/configuration-ingestor.d.ts +37 -40
- package/dist/lib/configuration-ingestor.js +93 -93
- package/dist/lib/configuration-ingestor.js.map +1 -1
- package/dist/lib/configure.d.ts +6 -6
- package/dist/lib/configure.js +14 -12
- package/dist/lib/configure.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -3
- package/dist/lib/constants.js +9 -11
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/context-id-generators.d.ts +3 -5
- package/dist/lib/context-id-generators.js +7 -6
- package/dist/lib/context-id-generators.js.map +1 -1
- package/dist/lib/end-session.d.ts +4 -4
- package/dist/lib/end-session.js +5 -5
- package/dist/lib/field.d.ts +24 -29
- package/dist/lib/field.js +41 -70
- package/dist/lib/field.js.map +1 -1
- package/dist/lib/index.d.ts +13 -13
- package/dist/lib/logger.d.ts +7 -6
- package/dist/lib/logger.js +7 -7
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/mount.d.ts +5 -5
- package/dist/lib/mount.js +12 -17
- package/dist/lib/mount.js.map +1 -1
- package/dist/lib/nunjucks-filters.d.ts +10 -12
- package/dist/lib/nunjucks-filters.js +35 -35
- package/dist/lib/nunjucks-filters.js.map +1 -1
- package/dist/lib/nunjucks.d.ts +7 -5
- package/dist/lib/nunjucks.js +10 -8
- package/dist/lib/nunjucks.js.map +1 -1
- package/dist/lib/utils.d.ts +19 -19
- package/dist/lib/utils.js +62 -55
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/validators/dateObject.d.ts +29 -22
- package/dist/lib/validators/dateObject.js +58 -49
- package/dist/lib/validators/dateObject.js.map +1 -1
- package/dist/lib/validators/email.d.ts +4 -4
- package/dist/lib/validators/email.js +4 -4
- package/dist/lib/validators/inArray.d.ts +4 -4
- package/dist/lib/validators/inArray.js +7 -8
- package/dist/lib/validators/inArray.js.map +1 -1
- package/dist/lib/validators/index.d.ts +10 -10
- package/dist/lib/validators/index.js +1 -3
- package/dist/lib/validators/index.js.map +1 -1
- package/dist/lib/validators/nino.d.ts +9 -8
- package/dist/lib/validators/nino.js +14 -10
- package/dist/lib/validators/nino.js.map +1 -1
- package/dist/lib/validators/postalAddressObject.d.ts +37 -24
- package/dist/lib/validators/postalAddressObject.js +65 -46
- package/dist/lib/validators/postalAddressObject.js.map +1 -1
- package/dist/lib/validators/range.d.ts +12 -8
- package/dist/lib/validators/range.js +11 -9
- package/dist/lib/validators/range.js.map +1 -1
- package/dist/lib/validators/regex.d.ts +4 -4
- package/dist/lib/validators/regex.js +5 -5
- package/dist/lib/validators/required.d.ts +6 -6
- package/dist/lib/validators/required.js +9 -11
- package/dist/lib/validators/required.js.map +1 -1
- package/dist/lib/validators/strlen.d.ts +12 -8
- package/dist/lib/validators/strlen.js +13 -11
- package/dist/lib/validators/strlen.js.map +1 -1
- package/dist/lib/validators/wordCount.d.ts +12 -8
- package/dist/lib/validators/wordCount.js +15 -11
- package/dist/lib/validators/wordCount.js.map +1 -1
- package/dist/lib/waypoint-url.d.ts +16 -13
- package/dist/lib/waypoint-url.js +39 -36
- package/dist/lib/waypoint-url.js.map +1 -1
- package/dist/middleware/body-parser.d.ts +1 -1
- package/dist/middleware/body-parser.js +6 -6
- package/dist/middleware/body-parser.js.map +1 -1
- package/dist/middleware/data.d.ts +1 -1
- package/dist/middleware/data.js +8 -7
- package/dist/middleware/data.js.map +1 -1
- package/dist/middleware/gather-fields.d.ts +2 -2
- package/dist/middleware/gather-fields.js +6 -4
- package/dist/middleware/gather-fields.js.map +1 -1
- package/dist/middleware/i18n.js +13 -15
- package/dist/middleware/i18n.js.map +1 -1
- package/dist/middleware/post.js +30 -18
- package/dist/middleware/post.js.map +1 -1
- package/dist/middleware/pre.d.ts +2 -2
- package/dist/middleware/pre.js +46 -26
- package/dist/middleware/pre.js.map +1 -1
- package/dist/middleware/progress-journey.d.ts +1 -1
- package/dist/middleware/progress-journey.js +5 -5
- package/dist/middleware/progress-journey.js.map +1 -1
- package/dist/middleware/sanitise-fields.d.ts +1 -1
- package/dist/middleware/sanitise-fields.js +13 -11
- package/dist/middleware/sanitise-fields.js.map +1 -1
- package/dist/middleware/serve-first-waypoint.d.ts +3 -3
- package/dist/middleware/serve-first-waypoint.js +8 -6
- package/dist/middleware/serve-first-waypoint.js.map +1 -1
- package/dist/middleware/session.js +14 -11
- package/dist/middleware/session.js.map +1 -1
- package/dist/middleware/skip-waypoint.d.ts +1 -1
- package/dist/middleware/skip-waypoint.js +3 -3
- package/dist/middleware/skip-waypoint.js.map +1 -1
- package/dist/middleware/steer-journey.d.ts +1 -1
- package/dist/middleware/steer-journey.js +16 -14
- package/dist/middleware/steer-journey.js.map +1 -1
- package/dist/middleware/strip-proxy-path.d.ts +1 -1
- package/dist/middleware/strip-proxy-path.js +3 -3
- package/dist/middleware/strip-proxy-path.js.map +1 -1
- package/dist/middleware/validate-fields.d.ts +1 -1
- package/dist/middleware/validate-fields.js +2 -5
- package/dist/middleware/validate-fields.js.map +1 -1
- package/dist/routes/ancillary.d.ts +3 -3
- package/dist/routes/ancillary.js +4 -4
- package/dist/routes/ancillary.js.map +1 -1
- package/dist/routes/journey.d.ts +2 -2
- package/dist/routes/journey.js +91 -39
- package/dist/routes/journey.js.map +1 -1
- package/dist/routes/static.d.ts +7 -5
- package/dist/routes/static.js +20 -20
- package/dist/routes/static.js.map +1 -1
- package/package.json +17 -16
- package/src/casa.js +134 -102
- package/src/lib/CasaTemplateLoader.js +24 -19
- package/src/lib/JourneyContext.js +147 -107
- package/src/lib/MutableRouter.js +72 -74
- package/src/lib/Plan.js +145 -97
- package/src/lib/ValidationError.js +25 -21
- package/src/lib/ValidatorFactory.js +17 -13
- package/src/lib/configuration-ingestor.js +147 -110
- package/src/lib/configure.js +34 -32
- package/src/lib/constants.js +9 -11
- package/src/lib/context-id-generators.js +40 -43
- package/src/lib/end-session.js +6 -6
- package/src/lib/field.js +74 -78
- package/src/lib/index.js +12 -12
- package/src/lib/logger.js +9 -9
- package/src/lib/mount.js +70 -80
- package/src/lib/nunjucks-filters.js +56 -59
- package/src/lib/nunjucks.js +23 -18
- package/src/lib/utils.js +78 -57
- package/src/lib/validators/dateObject.js +71 -60
- package/src/lib/validators/email.js +8 -8
- package/src/lib/validators/inArray.js +10 -11
- package/src/lib/validators/index.js +12 -14
- package/src/lib/validators/nino.js +29 -15
- package/src/lib/validators/postalAddressObject.js +87 -63
- package/src/lib/validators/range.js +14 -12
- package/src/lib/validators/regex.js +8 -8
- package/src/lib/validators/required.js +16 -16
- package/src/lib/validators/strlen.js +16 -14
- package/src/lib/validators/wordCount.js +22 -14
- package/src/lib/waypoint-url.js +64 -46
- package/src/middleware/body-parser.js +10 -10
- package/src/middleware/csrf.js +1 -1
- package/src/middleware/data.js +28 -24
- package/src/middleware/gather-fields.js +10 -9
- package/src/middleware/i18n.js +35 -37
- package/src/middleware/post.js +41 -21
- package/src/middleware/pre.js +62 -40
- package/src/middleware/progress-journey.js +32 -18
- package/src/middleware/sanitise-fields.js +43 -20
- package/src/middleware/serve-first-waypoint.js +14 -12
- package/src/middleware/session.js +74 -61
- package/src/middleware/skip-waypoint.js +7 -9
- package/src/middleware/steer-journey.js +40 -28
- package/src/middleware/strip-proxy-path.js +8 -7
- package/src/middleware/validate-fields.js +5 -12
- package/src/routes/ancillary.js +5 -7
- package/src/routes/journey.js +159 -85
- package/src/routes/static.js +62 -30
- package/views/casa/components/character-count/README.md +2 -2
- package/views/casa/components/checkboxes/README.md +6 -6
- package/views/casa/components/date-input/README.md +7 -7
- package/views/casa/components/input/README.md +2 -2
- package/views/casa/components/journey-form/README.md +33 -14
- package/views/casa/components/postal-address-object/README.md +4 -4
- package/views/casa/components/radios/README.md +6 -6
- package/views/casa/components/select/README.md +6 -6
- package/views/casa/components/textarea/README.md +2 -2
- package/views/casa/partials/scripts.njk +5 -3
- package/views/casa/partials/styles.njk +1 -4
- package/dist/assets/css/casa-ie8.css +0 -1
package/src/lib/configure.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { MemoryStore } from
|
|
2
|
-
import { resolve } from
|
|
3
|
-
import { createRequire } from
|
|
4
|
-
import cookieParserFactory from
|
|
5
|
-
import dirname from
|
|
1
|
+
import { MemoryStore } from "express-session";
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import { createRequire } from "module";
|
|
4
|
+
import cookieParserFactory from "cookie-parser";
|
|
5
|
+
import dirname from "./dirname.cjs";
|
|
6
6
|
|
|
7
|
-
import configurationIngestor from
|
|
8
|
-
import nunjucks from
|
|
9
|
-
import mountFactory from
|
|
7
|
+
import configurationIngestor from "./configuration-ingestor.js";
|
|
8
|
+
import nunjucks from "./nunjucks.js";
|
|
9
|
+
import mountFactory from "./mount.js";
|
|
10
10
|
|
|
11
|
-
import staticRoutes from
|
|
12
|
-
import ancillaryRoutes from
|
|
13
|
-
import journeyRoutes from
|
|
11
|
+
import staticRoutes from "../routes/static.js";
|
|
12
|
+
import ancillaryRoutes from "../routes/ancillary.js";
|
|
13
|
+
import journeyRoutes from "../routes/journey.js";
|
|
14
14
|
|
|
15
|
-
import preMiddlewareFactory from
|
|
16
|
-
import postMiddlewareFactory from
|
|
15
|
+
import preMiddlewareFactory from "../middleware/pre.js";
|
|
16
|
+
import postMiddlewareFactory from "../middleware/post.js";
|
|
17
17
|
|
|
18
|
-
import sessionMiddlewareFactory from
|
|
19
|
-
import i18nMiddlewareFactory from
|
|
20
|
-
import dataMiddlewareFactory from
|
|
18
|
+
import sessionMiddlewareFactory from "../middleware/session.js";
|
|
19
|
+
import i18nMiddlewareFactory from "../middleware/i18n.js";
|
|
20
|
+
import dataMiddlewareFactory from "../middleware/data.js";
|
|
21
21
|
|
|
22
|
-
import bodyParserMiddlewareFactory from
|
|
23
|
-
import csrfMiddlewareFactory from
|
|
22
|
+
import bodyParserMiddlewareFactory from "../middleware/body-parser.js";
|
|
23
|
+
import csrfMiddlewareFactory from "../middleware/csrf.js";
|
|
24
24
|
|
|
25
|
-
import { CONFIG_ERROR_VISIBILITY_ONSUBMIT } from
|
|
25
|
+
import { CONFIG_ERROR_VISIBILITY_ONSUBMIT } from "./constants.js";
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
+
* @typedef {import("../casa").ConfigurationOptions} ConfigurationOptions
|
|
28
29
|
* @access private
|
|
29
|
-
* @typedef {import('../casa').ConfigurationOptions} ConfigurationOptions
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
+
* @typedef {import("../casa").ConfigureResult} ConfigureResult
|
|
33
34
|
* @access private
|
|
34
|
-
* @typedef {import('../casa').ConfigureResult} ConfigureResult
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
+
* @typedef {import("../casa").Mounter} Mounter
|
|
38
39
|
* @access private
|
|
39
|
-
* @typedef {import('../casa').Mounter} Mounter
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -60,12 +60,12 @@ export default function configure(config = {}) {
|
|
|
60
60
|
errorVisibility = CONFIG_ERROR_VISIBILITY_ONSUBMIT,
|
|
61
61
|
views = [],
|
|
62
62
|
session = {
|
|
63
|
-
secret:
|
|
64
|
-
name:
|
|
63
|
+
secret: "secret",
|
|
64
|
+
name: "casasession",
|
|
65
65
|
secure: false,
|
|
66
66
|
ttl: 3600,
|
|
67
67
|
cookieSameSite: true,
|
|
68
|
-
cookiePath:
|
|
68
|
+
cookiePath: "/",
|
|
69
69
|
store: undefined,
|
|
70
70
|
},
|
|
71
71
|
pages = [],
|
|
@@ -75,7 +75,7 @@ export default function configure(config = {}) {
|
|
|
75
75
|
events = [],
|
|
76
76
|
i18n = {
|
|
77
77
|
dirs: [],
|
|
78
|
-
locales: [
|
|
78
|
+
locales: ["en", "cy"],
|
|
79
79
|
},
|
|
80
80
|
helmetConfigurator = undefined,
|
|
81
81
|
formMaxParams,
|
|
@@ -86,7 +86,7 @@ export default function configure(config = {}) {
|
|
|
86
86
|
// Prepare all page hooks so they are prefixed with the `journey.` scope.
|
|
87
87
|
pages.forEach((page) => {
|
|
88
88
|
/* eslint-disable-next-line no-param-reassign,no-return-assign */
|
|
89
|
-
(page?.hooks ?? []).forEach((h) => h.hook = `journey.${h.hook}`);
|
|
89
|
+
(page?.hooks ?? []).forEach((h) => (h.hook = `journey.${h.hook}`));
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
// Prepare a Nunjucks environment for rendering all templates.
|
|
@@ -94,8 +94,8 @@ export default function configure(config = {}) {
|
|
|
94
94
|
const nunjucksEnv = nunjucks({
|
|
95
95
|
views: [
|
|
96
96
|
...views,
|
|
97
|
-
resolve(dirname,
|
|
98
|
-
resolve(createRequire(dirname).resolve(
|
|
97
|
+
resolve(dirname, "../../views"),
|
|
98
|
+
resolve(createRequire(dirname).resolve("govuk-frontend"), "../../"),
|
|
99
99
|
],
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -120,7 +120,7 @@ export default function configure(config = {}) {
|
|
|
120
120
|
const i18nMiddleware = i18nMiddlewareFactory({
|
|
121
121
|
directories: [
|
|
122
122
|
// Order is important; latter directories take precedence
|
|
123
|
-
resolve(dirname,
|
|
123
|
+
resolve(dirname, "../../locales/"),
|
|
124
124
|
...i18n.dirs,
|
|
125
125
|
],
|
|
126
126
|
languages: i18n.locales,
|
|
@@ -148,7 +148,7 @@ export default function configure(config = {}) {
|
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
// Setup waypoint router, which includes routes for every defined waypoint
|
|
151
|
-
const globalErrorVisibility = errorVisibility
|
|
151
|
+
const globalErrorVisibility = errorVisibility;
|
|
152
152
|
const journeyRouter = journeyRoutes({
|
|
153
153
|
globalHooks: hooks,
|
|
154
154
|
pages,
|
|
@@ -207,7 +207,9 @@ export default function configure(config = {}) {
|
|
|
207
207
|
};
|
|
208
208
|
|
|
209
209
|
// Bootstrap all plugins
|
|
210
|
-
plugins
|
|
210
|
+
plugins
|
|
211
|
+
.filter((p) => p.bootstrap)
|
|
212
|
+
.forEach((plugin) => plugin?.bootstrap(configOutput));
|
|
211
213
|
|
|
212
214
|
// Finished configuration
|
|
213
215
|
return configOutput;
|
package/src/lib/constants.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
8
|
-
export const
|
|
9
|
-
export const
|
|
10
|
-
export const CONFIG_ERROR_VISIBILITY_ONSUBMIT = Symbol('onsubmit');
|
|
11
|
-
export const CONFIG_ERROR_VISIBILITY_ALWAYS = Symbol('always');
|
|
1
|
+
/** General-purpose references to the different request lifecycle phases. */
|
|
2
|
+
export const REQUEST_PHASE_STEER = Symbol("steer");
|
|
3
|
+
export const REQUEST_PHASE_SANITISE = Symbol("sanitise");
|
|
4
|
+
export const REQUEST_PHASE_GATHER = Symbol("gather");
|
|
5
|
+
export const REQUEST_PHASE_VALIDATE = Symbol("validate");
|
|
6
|
+
export const REQUEST_PHASE_REDIRECT = Symbol("redirect");
|
|
7
|
+
export const REQUEST_PHASE_RENDER = Symbol("render");
|
|
8
|
+
export const CONFIG_ERROR_VISIBILITY_ONSUBMIT = Symbol("onsubmit");
|
|
9
|
+
export const CONFIG_ERROR_VISIBILITY_ALWAYS = Symbol("always");
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/* eslint-disable import/no-cycle */
|
|
2
|
-
import { randomUUID } from
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* @typedef {import('../casa.js').ContextIdGenerator} ContextIdGenerator
|
|
6
|
-
*/
|
|
4
|
+
/** @typedef {import("../casa.js").ContextIdGenerator} ContextIdGenerator */
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
7
|
* Creates an instance of a UUID generator.
|
|
@@ -21,51 +19,50 @@ const uuid = () => () => randomUUID();
|
|
|
21
19
|
*
|
|
22
20
|
* @returns {ContextIdGenerator} Generator function
|
|
23
21
|
*/
|
|
24
|
-
const sequentialInteger =
|
|
25
|
-
|
|
22
|
+
const sequentialInteger =
|
|
23
|
+
() =>
|
|
24
|
+
({ reservedIds }) => {
|
|
25
|
+
const contextIds = Array.from(reservedIds).sort();
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
if (!contextIds.length) {
|
|
28
|
+
return "1";
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
// Find the first numeric ID that we can increment
|
|
32
|
+
let lastInSequence;
|
|
33
|
+
do {
|
|
34
|
+
lastInSequence = Number.parseInt(contextIds.pop(), 10);
|
|
35
|
+
} while (contextIds.length && Number.isNaN(lastInSequence));
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
};
|
|
37
|
+
return String(!Number.isNaN(lastInSequence) ? lastInSequence + 1 : 1);
|
|
38
|
+
};
|
|
39
39
|
|
|
40
|
-
const shortGuid =
|
|
41
|
-
length = 5,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Ambiguous characters excluded
|
|
46
|
-
const poolSize = pool.length;
|
|
40
|
+
const shortGuid =
|
|
41
|
+
({ length = 5, prefix = "", pool = "abcdefhkmnprtwxy346789" } = {}) =>
|
|
42
|
+
({ reservedIds }) => {
|
|
43
|
+
// Ambiguous characters excluded
|
|
44
|
+
const poolSize = pool.length;
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
const maxAttempts = 10;
|
|
47
|
+
let attempts = maxAttempts;
|
|
48
|
+
let id;
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
do {
|
|
51
|
+
id = Array(length)
|
|
52
|
+
.fill(0)
|
|
53
|
+
.map(() => pool.charAt(Math.floor(Math.random() * poolSize)))
|
|
54
|
+
.join("");
|
|
55
|
+
attempts--;
|
|
56
|
+
} while (attempts > 0 && reservedIds.includes(id));
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
if (attempts === 0) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Failed to generate GUID after ${maxAttempts} iterations`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
}
|
|
64
|
+
return `${prefix}${id}`;
|
|
65
|
+
};
|
|
63
66
|
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
*/
|
|
67
|
-
export {
|
|
68
|
-
uuid,
|
|
69
|
-
sequentialInteger,
|
|
70
|
-
shortGuid,
|
|
71
|
-
};
|
|
67
|
+
/** @namespace ContextIdGenerators */
|
|
68
|
+
export { uuid, sequentialInteger, shortGuid };
|
package/src/lib/end-session.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import logger from
|
|
1
|
+
import logger from "./logger.js";
|
|
2
2
|
|
|
3
|
-
const log = logger(
|
|
3
|
+
const log = logger("lib:end-session");
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* A convenience for ending the current session, but retaining some data in it,
|
|
7
|
-
* like the current language. It persists an empty session before regenerating
|
|
8
|
-
*
|
|
7
|
+
* like the current language. It persists an empty session before regenerating a
|
|
8
|
+
* new ID.
|
|
9
9
|
*
|
|
10
10
|
* Note: this will not remove the session from server-side storage, which will
|
|
11
11
|
* instead be left up to the storage mechanism to clean up.
|
|
12
12
|
*
|
|
13
13
|
* @memberof module:@dwp/govuk-casa
|
|
14
|
-
* @param {import(
|
|
14
|
+
* @param {import("express").Request} req HTTP request
|
|
15
15
|
* @param {Function} next Chain
|
|
16
16
|
* @returns {void}
|
|
17
17
|
*/
|
|
@@ -19,7 +19,7 @@ export default function endSession(req, next) {
|
|
|
19
19
|
const { language } = req.session;
|
|
20
20
|
|
|
21
21
|
Object.entries(req.session).forEach(([k]) => {
|
|
22
|
-
if (![
|
|
22
|
+
if (!["cookie"].includes(k)) {
|
|
23
23
|
// ESLint disabled as `Object.entries()` returns "own" properties, and
|
|
24
24
|
// all values are being null'd, so not assigned any user-controlled values
|
|
25
25
|
/* eslint-disable-next-line security/detect-object-injection */
|
package/src/lib/field.js
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
|
-
import lodash from
|
|
2
|
-
import { isEmpty } from
|
|
3
|
-
import logger from './logger.js';
|
|
1
|
+
import lodash from "lodash";
|
|
2
|
+
import { isEmpty } from "./utils.js";
|
|
4
3
|
|
|
5
|
-
const log = logger('lib:field');
|
|
6
4
|
const { isFunction } = lodash;
|
|
7
5
|
|
|
8
6
|
/**
|
|
7
|
+
* @typedef {import("./index").JourneyContext} JourneyContext
|
|
9
8
|
* @access private
|
|
10
|
-
* @typedef {import('./index').JourneyContext} JourneyContext
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
/**
|
|
12
|
+
* @typedef {import("../casa").Validator} Validator
|
|
14
13
|
* @access private
|
|
15
|
-
* @typedef {import('../casa').Validator} Validator
|
|
16
14
|
*/
|
|
17
15
|
|
|
18
16
|
/**
|
|
17
|
+
* @typedef {import("../casa").ValidateContext} ValidateContext
|
|
19
18
|
* @access private
|
|
20
|
-
* @typedef {import('../casa').ValidateContext} ValidateContext
|
|
21
19
|
*/
|
|
22
20
|
|
|
23
21
|
/**
|
|
22
|
+
* @typedef {import("../casa").ValidatorConditionFunction} ValidatorConditionFunction
|
|
24
23
|
* @access private
|
|
25
|
-
* @typedef {import('../casa').ValidatorConditionFunction} ValidatorConditionFunction
|
|
26
24
|
*/
|
|
27
25
|
|
|
28
26
|
/**
|
|
27
|
+
* @typedef {import("../casa").FieldProcessorFunction} FieldProcessorFunction
|
|
29
28
|
* @access private
|
|
30
|
-
* @typedef {import('../casa').FieldProcessorFunction} FieldProcessorFunction
|
|
31
29
|
*/
|
|
32
30
|
|
|
33
31
|
/**
|
|
32
|
+
* @typedef {import("./index").ValidationError} ValidationError
|
|
34
33
|
* @access private
|
|
35
|
-
* @typedef {import('./index').ValidationError} ValidationError
|
|
36
34
|
*/
|
|
37
35
|
|
|
38
36
|
// Quick check to see if the field name corresponds to a non-primitive complex
|
|
@@ -48,29 +46,19 @@ const reInvalidName = /[^a-z0-9_.\-[\]]/i;
|
|
|
48
46
|
* @class
|
|
49
47
|
*/
|
|
50
48
|
export class PageField {
|
|
51
|
-
/**
|
|
52
|
-
* @type {string}
|
|
53
|
-
*/
|
|
49
|
+
/** @type {string} */
|
|
54
50
|
#name;
|
|
55
51
|
|
|
56
|
-
/**
|
|
57
|
-
* @type {FieldProcessorFunction[]}
|
|
58
|
-
*/
|
|
52
|
+
/** @type {FieldProcessorFunction[]} */
|
|
59
53
|
#processors;
|
|
60
54
|
|
|
61
|
-
/**
|
|
62
|
-
* @type {Validator[]}
|
|
63
|
-
*/
|
|
55
|
+
/** @type {Validator[]} */
|
|
64
56
|
#validators;
|
|
65
57
|
|
|
66
|
-
/**
|
|
67
|
-
* @type {ValidatorConditionFunction[]}
|
|
68
|
-
*/
|
|
58
|
+
/** @type {ValidatorConditionFunction[]} */
|
|
69
59
|
#conditions;
|
|
70
60
|
|
|
71
|
-
/**
|
|
72
|
-
* @type {object}
|
|
73
|
-
*/
|
|
61
|
+
/** @type {object} */
|
|
74
62
|
#meta;
|
|
75
63
|
|
|
76
64
|
/**
|
|
@@ -78,12 +66,19 @@ export class PageField {
|
|
|
78
66
|
*
|
|
79
67
|
* @param {string} name Field name
|
|
80
68
|
* @param {object} [opts] Options
|
|
81
|
-
* @param {boolean} [opts.optional=false] Whether this field is optional
|
|
82
|
-
*
|
|
69
|
+
* @param {boolean} [opts.optional=false] Whether this field is optional.
|
|
70
|
+
* Default is `false`
|
|
71
|
+
* @param {boolean} [opts.persist=true] Whether this field will persist in
|
|
72
|
+
* `req.body`. Default is `true`
|
|
83
73
|
*/
|
|
84
|
-
constructor(
|
|
74
|
+
constructor(
|
|
75
|
+
name,
|
|
76
|
+
{ optional = false, persist = true } = Object.create(null),
|
|
77
|
+
) {
|
|
85
78
|
if (!name) {
|
|
86
|
-
throw new SyntaxError(
|
|
79
|
+
throw new SyntaxError(
|
|
80
|
+
"A name for this field is required, i.e. \"field('myField')\".",
|
|
81
|
+
);
|
|
87
82
|
}
|
|
88
83
|
|
|
89
84
|
this.#name = undefined;
|
|
@@ -139,7 +134,9 @@ export class PageField {
|
|
|
139
134
|
*/
|
|
140
135
|
getValue(obj = Object.create(null)) {
|
|
141
136
|
if (this.#meta.complex) {
|
|
142
|
-
return obj[this.#meta.complexFieldName]?.[
|
|
137
|
+
return obj[this.#meta.complexFieldName]?.[
|
|
138
|
+
this.#meta.complexFieldProperty
|
|
139
|
+
];
|
|
143
140
|
}
|
|
144
141
|
return obj[this.#name];
|
|
145
142
|
}
|
|
@@ -188,7 +185,9 @@ export class PageField {
|
|
|
188
185
|
*/
|
|
189
186
|
rename(name) {
|
|
190
187
|
if (reInvalidName.test(String(name))) {
|
|
191
|
-
throw new SyntaxError(
|
|
188
|
+
throw new SyntaxError(
|
|
189
|
+
`Field '${String(name)}' name contains invalid characters.`,
|
|
190
|
+
);
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
// Complex names are only supported to one level deep. For example,
|
|
@@ -196,7 +195,9 @@ export class PageField {
|
|
|
196
195
|
// early to aid developer.
|
|
197
196
|
const isComplex = reComplexType.test(name);
|
|
198
197
|
if (isComplex && name.match(/\[/g).length > 1) {
|
|
199
|
-
throw new SyntaxError(
|
|
198
|
+
throw new SyntaxError(
|
|
199
|
+
"Complex field names are only supported to 1 property depth. E.g. a[b] is ok, a[b][c] is not",
|
|
200
|
+
);
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
this.#name = String(name);
|
|
@@ -221,21 +222,19 @@ export class PageField {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
/**
|
|
224
|
-
* Add
|
|
225
|
-
*
|
|
226
|
-
* same time as other "processors".
|
|
225
|
+
* Add value validators Some validators will include a `sanitise()` method
|
|
226
|
+
* which will be run at the same time as other "processors".
|
|
227
227
|
*
|
|
228
228
|
* @param {Validator[]} items Validation functions
|
|
229
|
-
* @returns {PageField} Chain
|
|
230
|
-
* empty or missing, in v9 this functionality will removed in favour of the
|
|
231
|
-
* function getValidators().
|
|
229
|
+
* @returns {PageField} Chain
|
|
232
230
|
*/
|
|
233
231
|
validators(items = []) {
|
|
234
232
|
if (!items.length) {
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
throw new Error(
|
|
234
|
+
"Calling validators() to get all validators is no longer supported, please use getValidators()",
|
|
235
|
+
);
|
|
237
236
|
}
|
|
238
|
-
this.#validators = [...this.#validators, ...
|
|
237
|
+
this.#validators = [...this.#validators, ...items.flat()];
|
|
239
238
|
return this;
|
|
240
239
|
}
|
|
241
240
|
|
|
@@ -249,21 +248,20 @@ export class PageField {
|
|
|
249
248
|
}
|
|
250
249
|
|
|
251
250
|
/**
|
|
252
|
-
* Add
|
|
253
|
-
*
|
|
251
|
+
* Add value pre-processors This is most often used to sanitise values to a
|
|
252
|
+
* particular data type.
|
|
254
253
|
*
|
|
255
254
|
* @param {FieldProcessorFunction[]} items Processor functions
|
|
256
|
-
* @returns {PageField} Chain
|
|
257
|
-
* empty or missing, in v9 this functionality will removed in favour of the
|
|
258
|
-
* function getProcessors().
|
|
255
|
+
* @returns {PageField} Chain
|
|
259
256
|
*/
|
|
260
257
|
processors(items = []) {
|
|
261
258
|
if (!items.length) {
|
|
262
|
-
|
|
263
|
-
|
|
259
|
+
throw new Error(
|
|
260
|
+
"Calling processors() to get all processors is no longer supported, please use getProcessors()",
|
|
261
|
+
);
|
|
264
262
|
}
|
|
265
263
|
|
|
266
|
-
this.#processors = [...this.#processors, ...
|
|
264
|
+
this.#processors = [...this.#processors, ...items.flat()];
|
|
267
265
|
return this;
|
|
268
266
|
}
|
|
269
267
|
|
|
@@ -277,21 +275,19 @@ export class PageField {
|
|
|
277
275
|
}
|
|
278
276
|
|
|
279
277
|
/**
|
|
280
|
-
* Add
|
|
281
|
-
*
|
|
282
|
-
* "actionable".
|
|
278
|
+
* Add conditions All conditions must be met in order for this field to be
|
|
279
|
+
* considered "actionable".
|
|
283
280
|
*
|
|
284
281
|
* @param {ValidatorConditionFunction[]} items Condition functions
|
|
285
|
-
* @returns {PageField} Chain
|
|
286
|
-
* empty or missing, in v9 this functionality will removed in favour of the
|
|
287
|
-
* function getConditions().
|
|
282
|
+
* @returns {PageField} Chain
|
|
288
283
|
*/
|
|
289
284
|
conditions(items = []) {
|
|
290
285
|
if (!items.length) {
|
|
291
|
-
|
|
292
|
-
|
|
286
|
+
throw new Error(
|
|
287
|
+
"Calling conditions() to get all conditions is no longer supported, please use getConditions()",
|
|
288
|
+
);
|
|
293
289
|
}
|
|
294
|
-
this.#conditions = [...this.#conditions, ...
|
|
290
|
+
this.#conditions = [...this.#conditions, ...items.flat()];
|
|
295
291
|
return this;
|
|
296
292
|
}
|
|
297
293
|
|
|
@@ -300,22 +296,17 @@ export class PageField {
|
|
|
300
296
|
/**
|
|
301
297
|
* Run all validators and return array of errors, if applicable.
|
|
302
298
|
*
|
|
303
|
-
* @param {any} value Value to validate
|
|
304
299
|
* @param {ValidateContext} context Contextual validation information
|
|
305
300
|
* @returns {ValidationError[]} Errors, or an empty array if all valid
|
|
306
301
|
* @throws {TypeError} If validator does not return an array
|
|
307
302
|
*/
|
|
308
|
-
runValidators(
|
|
303
|
+
runValidators(context = Object.create(null)) {
|
|
309
304
|
// Skip validation if the field is empty and optional
|
|
310
|
-
if (this.#meta.optional && isEmpty(
|
|
305
|
+
if (this.#meta.optional && isEmpty(context?.fieldValue)) {
|
|
311
306
|
return [];
|
|
312
307
|
}
|
|
313
308
|
|
|
314
309
|
// Skip validation if conditions are not met
|
|
315
|
-
// We duplicate value in context.fieldValue for historical reasons
|
|
316
|
-
// @todo explain these historical reasons! And deprecate the need for
|
|
317
|
-
// `value` altogether
|
|
318
|
-
context.fieldValue = context.fieldValue ?? value;
|
|
319
310
|
if (!this.testConditions(context)) {
|
|
320
311
|
return [];
|
|
321
312
|
}
|
|
@@ -325,22 +316,26 @@ export class PageField {
|
|
|
325
316
|
// ESLint disabled as `i` is an integer
|
|
326
317
|
/* eslint-disable security/detect-object-injection */
|
|
327
318
|
// TODO: Replace `value` with `context.fieldValue` here
|
|
328
|
-
let fieldErrors = this.#validators[i].validate(
|
|
319
|
+
let fieldErrors = this.#validators[i].validate(
|
|
320
|
+
context.fieldValue,
|
|
321
|
+
context,
|
|
322
|
+
);
|
|
329
323
|
if (!Array.isArray(fieldErrors)) {
|
|
330
324
|
// Friendly message for developer
|
|
331
|
-
throw new TypeError(
|
|
325
|
+
throw new TypeError(
|
|
326
|
+
`The validator at index ${i} (name: ${this.#validators[i].name || "unknown"}) for field '${this.#name}' did not return an array`,
|
|
327
|
+
);
|
|
332
328
|
}
|
|
333
329
|
|
|
334
|
-
fieldErrors = fieldErrors.map((e) =>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
330
|
+
fieldErrors = fieldErrors.map((e) =>
|
|
331
|
+
e.withContext({
|
|
332
|
+
...context,
|
|
333
|
+
validator: this.#validators[i].name,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
338
336
|
/* eslint-enable security/detect-object-injection */
|
|
339
337
|
|
|
340
|
-
errors = [
|
|
341
|
-
...errors,
|
|
342
|
-
...(fieldErrors ?? []),
|
|
343
|
-
];
|
|
338
|
+
errors = [...errors, ...(fieldErrors ?? [])];
|
|
344
339
|
}
|
|
345
340
|
|
|
346
341
|
return errors;
|
|
@@ -385,7 +380,6 @@ export class PageField {
|
|
|
385
380
|
fieldName: this.#name,
|
|
386
381
|
fieldValue,
|
|
387
382
|
waypoint,
|
|
388
|
-
waypointId: waypoint, // [DEPRECATED] for backwards compatibility with v7
|
|
389
383
|
journeyContext,
|
|
390
384
|
};
|
|
391
385
|
|
|
@@ -447,8 +441,10 @@ export class PageField {
|
|
|
447
441
|
* @memberof module:@dwp/govuk-casa
|
|
448
442
|
* @param {string} name Field name
|
|
449
443
|
* @param {object} [opts] Options
|
|
450
|
-
* @param {boolean} [opts.optional=false] Whether this field is optional
|
|
451
|
-
*
|
|
444
|
+
* @param {boolean} [opts.optional=false] Whether this field is optional.
|
|
445
|
+
* Default is `false`
|
|
446
|
+
* @param {boolean} [opts.persist=true] Whether this field will persist in
|
|
447
|
+
* `req.body`. Default is `true`
|
|
452
448
|
* @returns {PageField} A PageField
|
|
453
449
|
*/
|
|
454
450
|
export default function field(name, opts) {
|
package/src/lib/index.js
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
* imported anywhere in code, other than JSDoc references.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import CasaTemplateLoader from
|
|
7
|
-
import configure from
|
|
8
|
-
import configurationIngestor from
|
|
9
|
-
import endSession from
|
|
10
|
-
import field, { PageField } from
|
|
11
|
-
import JourneyContext from
|
|
12
|
-
import MutableRouter from
|
|
13
|
-
import Plan from
|
|
14
|
-
import ValidationError from
|
|
15
|
-
import ValidatorFactory from
|
|
16
|
-
import waypointUrl from
|
|
17
|
-
import * as utils from
|
|
6
|
+
import CasaTemplateLoader from "./CasaTemplateLoader.js";
|
|
7
|
+
import configure from "./configure.js";
|
|
8
|
+
import configurationIngestor from "./configuration-ingestor.js";
|
|
9
|
+
import endSession from "./end-session.js";
|
|
10
|
+
import field, { PageField } from "./field.js";
|
|
11
|
+
import JourneyContext from "./JourneyContext.js";
|
|
12
|
+
import MutableRouter from "./MutableRouter.js";
|
|
13
|
+
import Plan from "./Plan.js";
|
|
14
|
+
import ValidationError from "./ValidationError.js";
|
|
15
|
+
import ValidatorFactory from "./ValidatorFactory.js";
|
|
16
|
+
import waypointUrl from "./waypoint-url.js";
|
|
17
|
+
import * as utils from "./utils.js";
|
|
18
18
|
|
|
19
19
|
export {
|
|
20
20
|
CasaTemplateLoader,
|
package/src/lib/logger.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import debug from
|
|
1
|
+
import debug from "debug";
|
|
2
2
|
|
|
3
|
-
const casaDebugger = debug(
|
|
3
|
+
const casaDebugger = debug("casa");
|
|
4
4
|
|
|
5
5
|
export default (namespace) => {
|
|
6
6
|
const logger = casaDebugger.extend(namespace);
|
|
7
7
|
|
|
8
8
|
return {
|
|
9
|
-
trace: logger.extend(
|
|
10
|
-
debug: logger.extend(
|
|
11
|
-
info: logger.extend(
|
|
12
|
-
warn: logger.extend(
|
|
13
|
-
error: logger.extend(
|
|
14
|
-
fatal: logger.extend(
|
|
9
|
+
trace: logger.extend("trace"),
|
|
10
|
+
debug: logger.extend("debug"),
|
|
11
|
+
info: logger.extend("info"),
|
|
12
|
+
warn: logger.extend("warn"),
|
|
13
|
+
error: logger.extend("error"),
|
|
14
|
+
fatal: logger.extend("fatal"),
|
|
15
15
|
};
|
|
16
|
-
}
|
|
16
|
+
};
|