@dwp/govuk-casa 9.0.0 → 9.2.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 +1 -1
- package/dist/assets/css/casa.css.map +1 -1
- package/dist/casa.d.ts +122 -95
- package/dist/casa.js +119 -86
- 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 +58 -40
- package/dist/lib/JourneyContext.js +132 -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 +20 -18
- package/dist/lib/field.js +35 -48
- 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 +11 -10
- 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 -27
- 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 +5 -9
- 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 -19
- package/dist/routes/static.js.map +1 -1
- package/package.json +20 -19
- package/src/casa.js +133 -100
- package/src/lib/CasaTemplateLoader.js +24 -19
- package/src/lib/JourneyContext.js +190 -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 +69 -58
- package/src/lib/index.js +12 -12
- package/src/lib/logger.js +9 -9
- package/src/lib/mount.js +70 -74
- 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 -41
- 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 +8 -15
- 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 -29
- 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/layouts/main.njk +2 -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,18 +222,19 @@ export class PageField {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
/**
|
|
224
|
-
* Add value validators
|
|
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
229
|
* @returns {PageField} Chain
|
|
230
230
|
*/
|
|
231
231
|
validators(items = []) {
|
|
232
232
|
if (!items.length) {
|
|
233
|
-
throw new Error(
|
|
233
|
+
throw new Error(
|
|
234
|
+
"Calling validators() to get all validators is no longer supported, please use getValidators()",
|
|
235
|
+
);
|
|
234
236
|
}
|
|
235
|
-
this.#validators = [...this.#validators, ...
|
|
237
|
+
this.#validators = [...this.#validators, ...items.flat()];
|
|
236
238
|
return this;
|
|
237
239
|
}
|
|
238
240
|
|
|
@@ -246,18 +248,20 @@ export class PageField {
|
|
|
246
248
|
}
|
|
247
249
|
|
|
248
250
|
/**
|
|
249
|
-
* Add value pre-processors
|
|
250
|
-
*
|
|
251
|
+
* Add value pre-processors This is most often used to sanitise values to a
|
|
252
|
+
* particular data type.
|
|
251
253
|
*
|
|
252
254
|
* @param {FieldProcessorFunction[]} items Processor functions
|
|
253
255
|
* @returns {PageField} Chain
|
|
254
256
|
*/
|
|
255
257
|
processors(items = []) {
|
|
256
258
|
if (!items.length) {
|
|
257
|
-
throw new Error(
|
|
259
|
+
throw new Error(
|
|
260
|
+
"Calling processors() to get all processors is no longer supported, please use getProcessors()",
|
|
261
|
+
);
|
|
258
262
|
}
|
|
259
263
|
|
|
260
|
-
this.#processors = [...this.#processors, ...
|
|
264
|
+
this.#processors = [...this.#processors, ...items.flat()];
|
|
261
265
|
return this;
|
|
262
266
|
}
|
|
263
267
|
|
|
@@ -271,18 +275,19 @@ export class PageField {
|
|
|
271
275
|
}
|
|
272
276
|
|
|
273
277
|
/**
|
|
274
|
-
* Add conditions
|
|
275
|
-
*
|
|
276
|
-
* "actionable".
|
|
278
|
+
* Add conditions All conditions must be met in order for this field to be
|
|
279
|
+
* considered "actionable".
|
|
277
280
|
*
|
|
278
281
|
* @param {ValidatorConditionFunction[]} items Condition functions
|
|
279
282
|
* @returns {PageField} Chain
|
|
280
283
|
*/
|
|
281
284
|
conditions(items = []) {
|
|
282
285
|
if (!items.length) {
|
|
283
|
-
throw new Error(
|
|
286
|
+
throw new Error(
|
|
287
|
+
"Calling conditions() to get all conditions is no longer supported, please use getConditions()",
|
|
288
|
+
);
|
|
284
289
|
}
|
|
285
|
-
this.#conditions = [...this.#conditions, ...
|
|
290
|
+
this.#conditions = [...this.#conditions, ...items.flat()];
|
|
286
291
|
return this;
|
|
287
292
|
}
|
|
288
293
|
|
|
@@ -311,22 +316,26 @@ export class PageField {
|
|
|
311
316
|
// ESLint disabled as `i` is an integer
|
|
312
317
|
/* eslint-disable security/detect-object-injection */
|
|
313
318
|
// TODO: Replace `value` with `context.fieldValue` here
|
|
314
|
-
let fieldErrors = this.#validators[i].validate(
|
|
319
|
+
let fieldErrors = this.#validators[i].validate(
|
|
320
|
+
context.fieldValue,
|
|
321
|
+
context,
|
|
322
|
+
);
|
|
315
323
|
if (!Array.isArray(fieldErrors)) {
|
|
316
324
|
// Friendly message for developer
|
|
317
|
-
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
|
+
);
|
|
318
328
|
}
|
|
319
329
|
|
|
320
|
-
fieldErrors = fieldErrors.map((e) =>
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
330
|
+
fieldErrors = fieldErrors.map((e) =>
|
|
331
|
+
e.withContext({
|
|
332
|
+
...context,
|
|
333
|
+
validator: this.#validators[i].name,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
324
336
|
/* eslint-enable security/detect-object-injection */
|
|
325
337
|
|
|
326
|
-
errors = [
|
|
327
|
-
...errors,
|
|
328
|
-
...(fieldErrors ?? []),
|
|
329
|
-
];
|
|
338
|
+
errors = [...errors, ...(fieldErrors ?? [])];
|
|
330
339
|
}
|
|
331
340
|
|
|
332
341
|
return errors;
|
|
@@ -432,8 +441,10 @@ export class PageField {
|
|
|
432
441
|
* @memberof module:@dwp/govuk-casa
|
|
433
442
|
* @param {string} name Field name
|
|
434
443
|
* @param {object} [opts] Options
|
|
435
|
-
* @param {boolean} [opts.optional=false] Whether this field is optional
|
|
436
|
-
*
|
|
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`
|
|
437
448
|
* @returns {PageField} A PageField
|
|
438
449
|
*/
|
|
439
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
|
+
};
|