@dwp/govuk-casa 7.0.6 → 8.0.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +22 -17
  2. package/dist/{casa → assets}/css/casa-ie8.css +1 -1
  3. package/dist/assets/css/casa.css +1 -0
  4. package/dist/casa.d.ts +10 -0
  5. package/dist/casa.js +44 -0
  6. package/dist/lib/CasaTemplateLoader.d.ts +19 -0
  7. package/dist/lib/CasaTemplateLoader.js +57 -0
  8. package/dist/lib/JourneyContext.d.ts +255 -0
  9. package/dist/lib/JourneyContext.js +681 -0
  10. package/dist/lib/MutableRouter.d.ts +155 -0
  11. package/dist/lib/MutableRouter.js +272 -0
  12. package/dist/lib/Plan.d.ts +119 -0
  13. package/dist/lib/Plan.js +382 -0
  14. package/dist/lib/ValidationError.d.ts +70 -0
  15. package/dist/lib/ValidationError.js +156 -0
  16. package/dist/lib/ValidatorFactory.d.ts +24 -0
  17. package/dist/lib/ValidatorFactory.js +87 -0
  18. package/dist/lib/configure.d.ts +205 -0
  19. package/dist/lib/configure.js +215 -0
  20. package/dist/lib/dirname.cjs +1 -0
  21. package/dist/lib/end-session.d.ts +12 -0
  22. package/dist/lib/end-session.js +24 -0
  23. package/dist/lib/field.d.ts +79 -0
  24. package/dist/lib/field.js +223 -0
  25. package/dist/lib/logger.d.ts +8 -0
  26. package/dist/lib/logger.js +19 -0
  27. package/dist/lib/nunjucks-filters.d.ts +26 -0
  28. package/dist/lib/nunjucks-filters.js +112 -0
  29. package/dist/lib/nunjucks.d.ts +22 -0
  30. package/dist/lib/nunjucks.js +49 -0
  31. package/dist/lib/utils.d.ts +22 -0
  32. package/dist/lib/utils.js +44 -0
  33. package/dist/lib/validators/dateObject.d.ts +4 -0
  34. package/dist/lib/validators/dateObject.js +135 -0
  35. package/dist/lib/validators/email.d.ts +4 -0
  36. package/dist/lib/validators/email.js +46 -0
  37. package/dist/lib/validators/inArray.d.ts +4 -0
  38. package/dist/lib/validators/inArray.js +60 -0
  39. package/dist/lib/validators/index.d.ts +21 -0
  40. package/dist/lib/validators/index.js +47 -0
  41. package/dist/lib/validators/nino.d.ts +4 -0
  42. package/dist/lib/validators/nino.js +46 -0
  43. package/dist/lib/validators/postalAddressObject.d.ts +4 -0
  44. package/dist/lib/validators/postalAddressObject.js +123 -0
  45. package/dist/lib/validators/regex.d.ts +4 -0
  46. package/dist/lib/validators/regex.js +40 -0
  47. package/dist/lib/validators/required.d.ts +4 -0
  48. package/dist/lib/validators/required.js +56 -0
  49. package/dist/lib/validators/strlen.d.ts +4 -0
  50. package/dist/lib/validators/strlen.js +51 -0
  51. package/dist/lib/validators/wordCount.d.ts +5 -0
  52. package/dist/lib/validators/wordCount.js +54 -0
  53. package/dist/lib/waypoint-url.d.ts +17 -0
  54. package/dist/lib/waypoint-url.js +46 -0
  55. package/dist/middleware/body-parser.d.ts +1 -0
  56. package/dist/middleware/body-parser.js +24 -0
  57. package/dist/middleware/csrf.d.ts +1 -0
  58. package/dist/middleware/csrf.js +31 -0
  59. package/dist/middleware/data.d.ts +6 -0
  60. package/dist/middleware/data.js +53 -0
  61. package/dist/middleware/dirname.cjs +1 -0
  62. package/dist/middleware/gather-fields.d.ts +5 -0
  63. package/dist/middleware/gather-fields.js +39 -0
  64. package/dist/middleware/i18n.d.ts +4 -0
  65. package/dist/middleware/i18n.js +87 -0
  66. package/dist/middleware/post.d.ts +1 -0
  67. package/dist/middleware/post.js +42 -0
  68. package/dist/middleware/pre.d.ts +3 -0
  69. package/dist/middleware/pre.js +38 -0
  70. package/dist/middleware/progress-journey.d.ts +6 -0
  71. package/dist/middleware/progress-journey.js +82 -0
  72. package/dist/middleware/sanitise-fields.d.ts +5 -0
  73. package/dist/middleware/sanitise-fields.js +48 -0
  74. package/dist/middleware/session.d.ts +10 -0
  75. package/dist/middleware/session.js +115 -0
  76. package/dist/middleware/skip-waypoint.d.ts +5 -0
  77. package/dist/middleware/skip-waypoint.js +40 -0
  78. package/dist/middleware/steer-journey.d.ts +6 -0
  79. package/dist/middleware/steer-journey.js +44 -0
  80. package/dist/middleware/validate-fields.d.ts +7 -0
  81. package/dist/middleware/validate-fields.js +76 -0
  82. package/dist/mjs/esm-wrapper.js +10 -0
  83. package/dist/mjs/package.json +3 -0
  84. package/dist/package.json +3 -0
  85. package/dist/routes/ancillary.d.ts +4 -0
  86. package/dist/routes/ancillary.js +19 -0
  87. package/dist/routes/dirname.cjs +1 -0
  88. package/dist/routes/journey.d.ts +8 -0
  89. package/dist/routes/journey.js +130 -0
  90. package/dist/routes/static.d.ts +26 -0
  91. package/dist/routes/static.js +67 -0
  92. package/package.json +45 -86
  93. package/views/casa/components/checkboxes/template.njk +4 -1
  94. package/views/casa/components/date-input/template.njk +3 -3
  95. package/views/casa/components/journey-form/README.md +3 -1
  96. package/views/casa/components/journey-form/template.njk +1 -1
  97. package/views/casa/components/postal-address-object/template.njk +5 -5
  98. package/views/casa/components/radios/template.njk +1 -1
  99. package/views/casa/layouts/journey.njk +26 -9
  100. package/views/casa/layouts/main.njk +6 -19
  101. package/views/casa/partials/scripts.njk +8 -3
  102. package/views/casa/partials/styles.njk +2 -2
  103. package/casa.js +0 -208
  104. package/definitions/review-page.js +0 -60
  105. package/dist/casa/css/casa.css +0 -1
  106. package/dist/casa/js/casa.js +0 -1
  107. package/index.d.ts +0 -121
  108. package/lib/ConfigIngestor.js +0 -588
  109. package/lib/GatherModifier.js +0 -14
  110. package/lib/I18n.js +0 -160
  111. package/lib/JourneyContext.d.ts +0 -97
  112. package/lib/JourneyContext.js +0 -552
  113. package/lib/JourneyMap.js +0 -233
  114. package/lib/JourneyRoad.js +0 -330
  115. package/lib/Logger.js +0 -59
  116. package/lib/PageDictionary.d.ts +0 -11
  117. package/lib/PageDirectory.js +0 -77
  118. package/lib/Plan.js +0 -423
  119. package/lib/RoadConverter.js +0 -153
  120. package/lib/UserJourney.js +0 -8
  121. package/lib/Util.js +0 -227
  122. package/lib/Validation.js +0 -20
  123. package/lib/bootstrap/end-session.js +0 -44
  124. package/lib/bootstrap/load-definitions.js +0 -64
  125. package/lib/commonBodyParser.js +0 -15
  126. package/lib/enums.js +0 -6
  127. package/lib/gather-modifiers/index.js +0 -7
  128. package/lib/gather-modifiers/trimPostalAddressObject.js +0 -75
  129. package/lib/gather-modifiers/trimWhitespace.js +0 -16
  130. package/lib/utils/createGetRequest.d.ts +0 -5
  131. package/lib/utils/createGetRequest.js +0 -59
  132. package/lib/utils/index.js +0 -11
  133. package/lib/utils/parseRequest.d.ts +0 -5
  134. package/lib/utils/parseRequest.js +0 -72
  135. package/lib/utils/sanitise.js +0 -74
  136. package/lib/utils/validate.js +0 -32
  137. package/lib/validation/ArrayObjectField.js +0 -49
  138. package/lib/validation/ObjectField.js +0 -53
  139. package/lib/validation/SimpleField.d.ts +0 -11
  140. package/lib/validation/SimpleField.js +0 -46
  141. package/lib/validation/ValidationError.d.ts +0 -14
  142. package/lib/validation/ValidationError.js +0 -170
  143. package/lib/validation/ValidatorFactory.d.ts +0 -32
  144. package/lib/validation/ValidatorFactory.js +0 -91
  145. package/lib/validation/index.js +0 -22
  146. package/lib/validation/processor/flattenErrorArray.js +0 -24
  147. package/lib/validation/processor/queue.js +0 -214
  148. package/lib/validation/processor.js +0 -84
  149. package/lib/validation/rules/README.md +0 -3
  150. package/lib/validation/rules/ValidationRules.d.ts +0 -22
  151. package/lib/validation/rules/dateObject.js +0 -156
  152. package/lib/validation/rules/email.js +0 -44
  153. package/lib/validation/rules/inArray.js +0 -61
  154. package/lib/validation/rules/index.js +0 -23
  155. package/lib/validation/rules/nino.js +0 -48
  156. package/lib/validation/rules/optional.js +0 -14
  157. package/lib/validation/rules/postalAddressObject.js +0 -142
  158. package/lib/validation/rules/regex.js +0 -39
  159. package/lib/validation/rules/required.js +0 -57
  160. package/lib/validation/rules/strlen.js +0 -57
  161. package/lib/validation/rules/wordCount.js +0 -61
  162. package/lib/view-filters/formatDateObject.js +0 -35
  163. package/lib/view-filters/includes.js +0 -10
  164. package/lib/view-filters/index.js +0 -23
  165. package/lib/view-filters/mergeObjectsDeep.js +0 -21
  166. package/lib/view-filters/renderAsAttributes.js +0 -33
  167. package/middleware/errors/404.js +0 -12
  168. package/middleware/errors/catch-all.js +0 -27
  169. package/middleware/errors/index.js +0 -9
  170. package/middleware/headers/config-defaults.js +0 -57
  171. package/middleware/headers/headers.js +0 -40
  172. package/middleware/headers/index.js +0 -9
  173. package/middleware/i18n/i18n.js +0 -56
  174. package/middleware/i18n/index.js +0 -16
  175. package/middleware/index.js +0 -55
  176. package/middleware/mount/index.js +0 -9
  177. package/middleware/mount/mount.js +0 -10
  178. package/middleware/nunjucks/environment.js +0 -57
  179. package/middleware/nunjucks/index.js +0 -8
  180. package/middleware/page/csrf.js +0 -37
  181. package/middleware/page/edit-mode.js +0 -52
  182. package/middleware/page/gather.js +0 -75
  183. package/middleware/page/index.js +0 -103
  184. package/middleware/page/journey-continue.js +0 -157
  185. package/middleware/page/journey-rails.js +0 -102
  186. package/middleware/page/prepare-request.js +0 -77
  187. package/middleware/page/render.js +0 -75
  188. package/middleware/page/skip.js +0 -72
  189. package/middleware/page/utils.js +0 -206
  190. package/middleware/page/validate.js +0 -67
  191. package/middleware/session/expiry.js +0 -95
  192. package/middleware/session/genid.js +0 -18
  193. package/middleware/session/index.js +0 -18
  194. package/middleware/session/init.js +0 -25
  195. package/middleware/session/seed.js +0 -50
  196. package/middleware/session/timeout.js +0 -5
  197. package/middleware/static/asset-versions.js +0 -23
  198. package/middleware/static/index.js +0 -104
  199. package/middleware/static/prepare-assets.js +0 -51
  200. package/middleware/static/serve-assets.js +0 -58
  201. package/middleware/variables/index.js +0 -12
  202. package/middleware/variables/variables.js +0 -35
  203. package/src/browserconfig.xml +0 -5
  204. package/src/js/casa.js +0 -132
  205. package/src/scss/_casaElements.scss +0 -11
  206. package/src/scss/_casaGovukTemplateJinjaPolyfill.scss +0 -39
  207. package/src/scss/_casaMountUrl.scss +0 -8
  208. package/src/scss/casa-ie8.scss +0 -3
  209. package/src/scss/casa.scss +0 -14
  210. package/test/unit/templates/README.md +0 -5
  211. package/test/utils/BaseTestWaypoint.js +0 -106
  212. package/test/utils/concatWaypoints.js +0 -26
  213. package/test/utils/index.js +0 -6
  214. package/test/utils/testTraversal.js +0 -90
  215. package/views/casa/partials/cookie_message.njk +0 -3
  216. package/views/casa/partials/phase_banner_alpha.njk +0 -8
  217. package/views/casa/partials/phase_banner_beta.njk +0 -8
  218. package/views/casa/review/page-block.njk +0 -8
  219. package/views/casa/review/review.njk +0 -47
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // Mark a waypoint as skipped
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const lodash_1 = require("lodash");
8
+ const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
9
+ const waypoint_url_js_1 = __importDefault(require("../lib/waypoint-url.js"));
10
+ const logger_js_1 = __importDefault(require("../lib/logger.js"));
11
+ const log = (0, logger_js_1.default)('middleware:skip-waypoint');
12
+ exports.default = ({ waypoint, mountUrl, }) => [
13
+ (req, res, next) => {
14
+ if (!(0, lodash_1.has)(req.query, 'skipto')) {
15
+ return next();
16
+ }
17
+ const skipTo = String(req.query.skipto);
18
+ // Inject a special `__skipped__` attribute into this waypoint's data
19
+ log.info(`Marking waypoint "${waypoint}" as skipped`);
20
+ req.casa.journeyContext.clearValidationErrorsForPage(waypoint);
21
+ req.casa.journeyContext.setDataForPage(waypoint, {
22
+ __skipped__: true,
23
+ });
24
+ JourneyContext_js_1.default.putContext(req.session, req.casa.journeyContext);
25
+ const redirectUrl = (0, waypoint_url_js_1.default)({
26
+ mountUrl,
27
+ waypoint: skipTo,
28
+ edit: req.editMode,
29
+ editOrigin: req.editOriginUrl,
30
+ journeyContext: req.casa.journeyContext,
31
+ });
32
+ log.debug(`Will redirect to "${redirectUrl}" after skipping "${waypoint}"`);
33
+ req.session.save((err) => {
34
+ if (err) {
35
+ return next(err);
36
+ }
37
+ res.redirect(302, redirectUrl);
38
+ });
39
+ },
40
+ ];
@@ -0,0 +1,6 @@
1
+ declare function _default({ waypoint, plan, mountUrl, }: {
2
+ waypoint: string;
3
+ plan: any;
4
+ mountUrl: string;
5
+ }): ((req: any, res: any, next: any) => any)[];
6
+ export default _default;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // This sits in front of all other middleware and prevents the user from
3
+ // "jumping ahead" in the Plan.
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const waypoint_url_js_1 = __importDefault(require("../lib/waypoint-url.js"));
9
+ const logger_js_1 = __importDefault(require("../lib/logger.js"));
10
+ const log = (0, logger_js_1.default)('middleware:steer-journey');
11
+ /**
12
+ * @param {Object} obj
13
+ * @param {string} obj.waypoint
14
+ * @param {Plan} obj.plan
15
+ * @param {string} obj.mountUrl
16
+ */
17
+ exports.default = ({ waypoint, plan, mountUrl, }) => [
18
+ (req, res, next) => {
19
+ // If the requested waypoint doesn't exist in the traversed journey, send
20
+ // the user back to the last good waypoint.
21
+ const traversed = plan.traverse(req.casa.journeyContext);
22
+ if (traversed.indexOf(waypoint) === -1) {
23
+ const redirectTo = traversed[traversed.length - 1];
24
+ log.trace(`Attempted to access "${waypoint}" when not in the journey; redirecting to "${redirectTo}"`);
25
+ return res.redirect(302, (0, waypoint_url_js_1.default)({
26
+ waypoint: redirectTo,
27
+ mountUrl,
28
+ journeyContext: req.casa.journeyContext,
29
+ edit: req.casa.editMode,
30
+ editOrigin: req.casa.editOrigin,
31
+ }));
32
+ }
33
+ // difficult: first waypoint on a Plan - how do we determine if there are other plans pointing at this one?
34
+ // and how do we determine if those others are part of a future plan, or a past one?
35
+ // Think we'll have to leave it up to the dev to add the back link for the first page in a Plan.
36
+ // Calculate URL for the "back" link
37
+ const [prevRoute] = plan.traversePrevRoutes(req.casa.journeyContext, {
38
+ startWaypoint: waypoint,
39
+ stopCondition: () => (true), // stop at the first one
40
+ });
41
+ res.locals.casa.journeyPreviousUrl = prevRoute.target ? (0, waypoint_url_js_1.default)({ mountUrl, waypoint: prevRoute.target, routeName: 'prev' }) : undefined;
42
+ next();
43
+ },
44
+ ];
@@ -0,0 +1,7 @@
1
+ declare function _default({ waypoint, fields, mountUrl, plan, }: {
2
+ waypoint: any;
3
+ fields?: any[] | undefined;
4
+ mountUrl: any;
5
+ plan: any;
6
+ }): ((req: any, res: any, next: any) => any)[];
7
+ export default _default;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // Validate the data captured in the journey context
7
+ const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
8
+ const updateContext = ({ waypoint, errors = null, plan, mountUrl, journeyContext, session, }) => {
9
+ // Set validation state
10
+ if (errors === null) {
11
+ journeyContext.clearValidationErrorsForPage(waypoint);
12
+ }
13
+ else {
14
+ journeyContext.setValidationErrorsForPage(waypoint, errors);
15
+ }
16
+ // // Update nav context
17
+ // // In most cases, the "next" & "prev" routes will result in the same sequence,
18
+ // // in reverse. But devs do have the option of setting different logic on
19
+ // // these routes, so this is the proper way to do it.
20
+ // const traversedNext = plan.traverseNextRoutes(journeyContext).map(r => r.source);
21
+ // const traversedPrev = plan.traversePrevRoutes(journeyContext, {
22
+ // startWaypoint: traversedNext[traversedNext.length - 1],
23
+ // }).map(r => r.source);
24
+ // journeyContext.setNavigationUrls(mountUrl, traversedNext, 'next');
25
+ // journeyContext.setNavigationUrls(mountUrl, traversedPrev, 'prev');
26
+ // Save to session
27
+ JourneyContext_js_1.default.putContext(session, journeyContext);
28
+ };
29
+ exports.default = ({ waypoint, fields = [], mountUrl, plan, }) => [
30
+ (req, res, next) => {
31
+ var _a, _b;
32
+ let errors = [];
33
+ for (let i = 0, l = fields.length; i < l; i++) {
34
+ const field = fields[i];
35
+ const fieldName = field.name;
36
+ const fieldValue = (_b = (_a = req.casa.journeyContext.data) === null || _a === void 0 ? void 0 : _a[waypoint]) === null || _b === void 0 ? void 0 : _b[fieldName];
37
+ const context = {
38
+ fieldName,
39
+ fieldValue,
40
+ waypoint,
41
+ journeyContext: req.casa.journeyContext,
42
+ };
43
+ if (!field.testConditions(context))
44
+ continue;
45
+ errors = [
46
+ ...errors,
47
+ ...field.runValidators(fieldValue, context),
48
+ ];
49
+ }
50
+ // Validation passed with no errors
51
+ if (!errors.length) {
52
+ updateContext({
53
+ waypoint,
54
+ session: req.session,
55
+ mountUrl,
56
+ plan,
57
+ journeyContext: req.casa.journeyContext,
58
+ });
59
+ return next();
60
+ }
61
+ // If there are any native errors in the list, we need to bail the request
62
+ if (errors.find((e) => e instanceof Error)) {
63
+ return next(e);
64
+ }
65
+ // Make the errors available to downstream middleware
66
+ updateContext({
67
+ errors,
68
+ waypoint,
69
+ session: req.session,
70
+ mountUrl,
71
+ plan,
72
+ journeyContext: req.casa.journeyContext,
73
+ });
74
+ next();
75
+ }
76
+ ];
@@ -0,0 +1,10 @@
1
+ // Basic wrapper to act as the package entrypoint for ESM applications
2
+ // ref: https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1
3
+ import casa from '../casa.js';
4
+ export const configure = casa.configure;
5
+ export const validators = casa.validators;
6
+ export const field = casa.field;
7
+ export const Plan = casa.Plan;
8
+ export const JourneyContext = casa.JourneyContext;
9
+ export const ValidationError = casa.ValidationError;
10
+ export const waypointUrl = casa.waypointUrl;
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,4 @@
1
+ export default function ancillaryRouter({ sessionTtl, }: {
2
+ sessionTtl: any;
3
+ }): MutableRouter;
4
+ import MutableRouter from "../lib/MutableRouter.js";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const MutableRouter_js_1 = __importDefault(require("../lib/MutableRouter.js"));
7
+ function ancillaryRouter({ sessionTtl, }) {
8
+ // Router
9
+ const router = new MutableRouter_js_1.default();
10
+ // Session timeout
11
+ // TODO: add a `ancillary.presessiontimeout` hook here? Might be useful for those who way to enhance the timeout route, rather than replacing it completely
12
+ router.all('/session-timeout', (req, res) => {
13
+ res.render('casa/session-timeout.njk', {
14
+ sessionTtl: Math.floor(sessionTtl / 60),
15
+ });
16
+ });
17
+ return router;
18
+ }
19
+ exports.default = ancillaryRouter;
@@ -0,0 +1 @@
1
+ module.exports = __dirname;
@@ -0,0 +1,8 @@
1
+ export default function journeyRouter({ globalHooks, pages, plan, csrfMiddleware, mountUrl, }: {
2
+ globalHooks: any;
3
+ pages: any;
4
+ plan: any;
5
+ csrfMiddleware: any;
6
+ mountUrl: any;
7
+ }): MutableRouter;
8
+ import MutableRouter from "../lib/MutableRouter.js";
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable object-curly-newline,max-len */
7
+ const MutableRouter_js_1 = __importDefault(require("../lib/MutableRouter.js"));
8
+ const skip_waypoint_js_1 = __importDefault(require("../middleware/skip-waypoint.js"));
9
+ const steer_journey_js_1 = __importDefault(require("../middleware/steer-journey.js"));
10
+ const sanitise_fields_js_1 = __importDefault(require("../middleware/sanitise-fields.js"));
11
+ const gather_fields_js_1 = __importDefault(require("../middleware/gather-fields.js"));
12
+ const validate_fields_js_1 = __importDefault(require("../middleware/validate-fields.js"));
13
+ const progress_journey_js_1 = __importDefault(require("../middleware/progress-journey.js"));
14
+ const waypoint_url_js_1 = __importDefault(require("../lib/waypoint-url.js"));
15
+ const logger_js_1 = __importDefault(require("../lib/logger.js"));
16
+ const log = (0, logger_js_1.default)('router:journey');
17
+ const resolveHooks = (hookName, waypoint, pageHooks, globalHooks = []) => {
18
+ const waypointPath = `/${waypoint}`;
19
+ const pathMatch = (h) => h.path === undefined || (h.path instanceof RegExp && h.path.test(waypointPath)) || h.path === waypointPath;
20
+ const matchedPageHooks = (pageHooks || []).filter((h) => `journey.${h.hook}` === hookName).map((h) => h.middleware);
21
+ const matchedGlobalHooks = globalHooks.filter((h) => h.hook === hookName).filter(pathMatch).map((h) => h.middleware);
22
+ return [
23
+ ...matchedGlobalHooks,
24
+ ...matchedPageHooks,
25
+ ];
26
+ };
27
+ const renderMiddlewareFactory = (view, contextFactory) => [
28
+ (req, res, next) => {
29
+ res.render(view, Object.assign({
30
+ // Common template variables for both GET and POST requests
31
+ inEditMode: req.casa.editMode, editOriginUrl: req.casa.editOrigin,
32
+ // editSearchParams: req.editSearchParams,
33
+ activeContextId: req.casa.journeyContext.identity.id }, contextFactory(req)), (err, templateString) => {
34
+ if (err) {
35
+ // logger.error(err);
36
+ next(err);
37
+ }
38
+ else {
39
+ res.send(templateString);
40
+ }
41
+ });
42
+ },
43
+ ];
44
+ function journeyRouter({ globalHooks, pages, plan, csrfMiddleware, mountUrl, }) {
45
+ // Router
46
+ const router = new MutableRouter_js_1.default();
47
+ // Special "_" route which handles redirecting the user between sub-apps
48
+ // /app1/_/?refmount=app2&route=prev
49
+ // - will redirect to the
50
+ router.all('/_', (req, res) => {
51
+ var _a, _b;
52
+ const refmount = (_a = req.query) === null || _a === void 0 ? void 0 : _a.refmount;
53
+ const route = (_b = req.query) === null || _b === void 0 ? void 0 : _b.route;
54
+ log.trace(`App root ${mountUrl}: refmount = ${refmount}, route = ${route}`);
55
+ let redirectTo;
56
+ const fallback = (0, waypoint_url_js_1.default)({
57
+ mountUrl,
58
+ waypoint: plan.traverse(req.casa.journeyContext, {
59
+ stopCondition: () => (true), // we only need one; stop at the first
60
+ })[0],
61
+ });
62
+ if (route === 'prev') {
63
+ const routes = plan.traversePrevRoutes(req.casa.journeyContext, { startWaypoint: refmount });
64
+ redirectTo = routes.length ? (0, waypoint_url_js_1.default)({ mountUrl, waypoint: routes[0].target }) : fallback;
65
+ }
66
+ else {
67
+ const routes = plan.traverseNextRoutes(req.casa.journeyContext, { startWaypoint: refmount });
68
+ if (routes[0].target !== null) {
69
+ redirectTo = routes.length ? (0, waypoint_url_js_1.default)({ mountUrl, waypoint: routes[0].target }) : fallback;
70
+ }
71
+ else {
72
+ redirectTo = fallback;
73
+ }
74
+ }
75
+ // Carry over any params
76
+ const url = new URL(redirectTo, 'https://placeholder.test/');
77
+ const searchParams = new URLSearchParams(req.query);
78
+ searchParams.delete('refmount');
79
+ searchParams.delete('route');
80
+ url.search = searchParams.toString();
81
+ redirectTo = `${url.pathname.replace(/\/+/g, '/')}${url.search}`;
82
+ log.trace(`Redirect to ${redirectTo}`);
83
+ return res.redirect(redirectTo);
84
+ });
85
+ // Create GET / POST routes for each page
86
+ const commonMiddleware = [
87
+ ...csrfMiddleware,
88
+ ];
89
+ pages.forEach((page) => {
90
+ const { waypoint, view, hooks: pageHooks, fields } = page;
91
+ const formUrl = (0, waypoint_url_js_1.default)({ mountUrl, waypoint });
92
+ const waypointPath = `/${waypoint}`;
93
+ const commonWaypointMiddleware = [
94
+ (req, res, next) => {
95
+ req.casa.waypoint = waypoint;
96
+ next();
97
+ },
98
+ ...(0, skip_waypoint_js_1.default)({ mountUrl, waypoint }),
99
+ ];
100
+ router.get(waypointPath, ...commonMiddleware, ...commonWaypointMiddleware, ...resolveHooks('journey.presteer', waypoint, pageHooks, globalHooks), ...(0, steer_journey_js_1.default)({ waypoint, mountUrl, plan }), ...resolveHooks('journey.poststeer', waypoint, pageHooks, globalHooks), ...resolveHooks('journey.prerender', waypoint, pageHooks, globalHooks), renderMiddlewareFactory(view, (req) => ({
101
+ formUrl,
102
+ formData: req.casa.journeyContext.getDataForPage(waypoint),
103
+ })));
104
+ router.post(waypointPath, ...commonMiddleware, ...commonWaypointMiddleware, ...resolveHooks('journey.presteer', waypoint, pageHooks, globalHooks), ...(0, steer_journey_js_1.default)({ waypoint, mountUrl, plan }), ...resolveHooks('journey.poststeer', waypoint, pageHooks, globalHooks), ...resolveHooks('journey.presanitise', waypoint, pageHooks, globalHooks), ...(0, sanitise_fields_js_1.default)({ waypoint, fields }), ...resolveHooks('journey.postsanitise', waypoint, pageHooks, globalHooks), ...resolveHooks('journey.pregather', waypoint, pageHooks, globalHooks), ...(0, gather_fields_js_1.default)({ waypoint, fields }), ...resolveHooks('journey.postgather', waypoint, pageHooks, globalHooks), ...resolveHooks('journey.prevalidate', waypoint, pageHooks, globalHooks), ...(0, validate_fields_js_1.default)({ waypoint, fields, mountUrl, plan }), ...resolveHooks('journey.postvalidate', waypoint, pageHooks, globalHooks),
105
+ // If there were validation errors, jump out of this route and into the
106
+ // next, where the errors will be rendered
107
+ (req, res, next) => (req.casa.journeyContext.hasValidationErrorsForPage(waypoint) ? next('route') : next()), ...resolveHooks('journey.preredirect', waypoint, pageHooks, globalHooks), ...(0, progress_journey_js_1.default)({ waypoint, plan, mountUrl }));
108
+ router.post(waypointPath, ...resolveHooks('journey.prerender', waypoint, pageHooks, globalHooks), renderMiddlewareFactory(view, (req) => {
109
+ var _a;
110
+ const errors = (_a = req.casa.journeyContext.getValidationErrorsForPageByField(waypoint)) !== null && _a !== void 0 ? _a : Object.create(null);
111
+ // This is a convenience for the template. The `govukErrorSummary` macro
112
+ // requires the errors be in a particular format, so here we provide our
113
+ // errors in that format.
114
+ // Where there are multiple errors against a particular field, only the
115
+ // first one is shown.
116
+ const govukErrors = Object.keys(errors).map((k) => ({
117
+ text: req.t(errors[k][0].summary, errors[k][0].variables),
118
+ href: errors[k][0].fieldHref,
119
+ }));
120
+ return {
121
+ formUrl,
122
+ formData: req.body,
123
+ formErrors: Object.keys(errors).length ? errors : null,
124
+ formErrorsGovukArray: govukErrors.length ? govukErrors : null,
125
+ };
126
+ }));
127
+ });
128
+ return router;
129
+ }
130
+ exports.default = journeyRouter;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @typedef {object} StaticOptions Options to configure static router
3
+ * @property {string} [mountUrl=/] URL prefix for govuk-frontend static assets (optional, default /)
4
+ * @property {number} [maxAge=3600000] Cache TTL for all assets (optional, default 1 hour)
5
+ */
6
+ /**
7
+ * Create a router for serving CASA's static assets.
8
+ *
9
+ * @param {StaticOptions} options Options
10
+ * @returns {MutableRouter} ExpressJS Router instance
11
+ */
12
+ export default function staticRouter({ mountUrl, maxAge, }: StaticOptions): MutableRouter;
13
+ /**
14
+ * Options to configure static router
15
+ */
16
+ export type StaticOptions = {
17
+ /**
18
+ * )
19
+ */
20
+ mountUrl?: string | undefined;
21
+ /**
22
+ * Cache TTL for all assets (optional, default 1 hour)
23
+ */
24
+ maxAge?: number | undefined;
25
+ };
26
+ import MutableRouter from "../lib/MutableRouter.js";
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = require("express");
7
+ const fs_1 = require("fs");
8
+ const url_1 = require("url");
9
+ const path_1 = require("path");
10
+ const module_1 = require("module");
11
+ const dirname_cjs_1 = __importDefault(require("./dirname.cjs"));
12
+ const MutableRouter_js_1 = __importDefault(require("../lib/MutableRouter.js"));
13
+ const oneDay = 86400000;
14
+ /**
15
+ * @typedef {object} StaticOptions Options to configure static router
16
+ * @property {string} [mountUrl=/] URL prefix for govuk-frontend static assets (optional, default /)
17
+ * @property {number} [maxAge=3600000] Cache TTL for all assets (optional, default 1 hour)
18
+ */
19
+ /**
20
+ * Create a router for serving CASA's static assets.
21
+ *
22
+ * @param {StaticOptions} options Options
23
+ * @returns {MutableRouter} ExpressJS Router instance
24
+ */
25
+ function staticRouter({ mountUrl = '/', maxAge = 3600000, }) {
26
+ const staticRouter = new MutableRouter_js_1.default();
27
+ const notFoundHandler = (req, res, next) => {
28
+ // Fall through to a general purpose error handler
29
+ next(new Error('404'));
30
+ };
31
+ const setHeaders = (req, res, next) => {
32
+ var _a;
33
+ res.set('cache-control', 'public');
34
+ res.set('pragma', 'cache');
35
+ res.set('expires', new Date(Date.now() + oneDay).toUTCString());
36
+ const { pathname } = new url_1.URL((_a = req === null || req === void 0 ? void 0 : req.originalUrl) !== null && _a !== void 0 ? _a : '', 'http://placeholder.test/');
37
+ if (pathname.substr(-4) === '.css') {
38
+ // Just needed for our in-memory CSS assets
39
+ res.set('content-type', 'text/css');
40
+ }
41
+ next();
42
+ };
43
+ const staticConfig = {
44
+ etag: true,
45
+ lastModified: false,
46
+ maxAge,
47
+ setHeaders: (res) => {
48
+ setHeaders(null, res, () => { });
49
+ },
50
+ };
51
+ // The CASA CSS source contains the placeholder `~~~CASA_MOUNT_URL~~~` which
52
+ // must be replaced with the dynamic `mountUrl` to ensure govuk-frontend
53
+ // assets are served from the correct location.
54
+ const casaCss = (0, fs_1.readFileSync)((0, path_1.resolve)(dirname_cjs_1.default, '../../dist/assets/css/casa.css'), { encoding: 'utf8' }).replace(/~~~CASA_MOUNT_URL~~~/g, mountUrl);
55
+ const casaCssIe8 = (0, fs_1.readFileSync)((0, path_1.resolve)(dirname_cjs_1.default, '../../dist/assets/css/casa-ie8.css'), { encoding: 'utf8' }).replace(/~~~CASA_MOUNT_URL~~~/g, mountUrl);
56
+ // The static middleware will only server GET/HEAD requests, so we can mount
57
+ // the middleware using `use()` rather than resorting to `get()`
58
+ const govukFrontendDirectory = (0, path_1.resolve)((0, module_1.createRequire)(dirname_cjs_1.default).resolve('govuk-frontend'), '../../');
59
+ staticRouter.use('/govuk/assets/js/all.js', (0, express_1.static)(`${govukFrontendDirectory}/govuk/all.js`, staticConfig));
60
+ staticRouter.use('/govuk/assets', (0, express_1.static)(`${govukFrontendDirectory}/govuk/assets`, staticConfig));
61
+ staticRouter.use('/govuk/assets', notFoundHandler);
62
+ staticRouter.use('/casa/assets/css/casa.css', setHeaders, (req, res) => res.send(casaCss));
63
+ staticRouter.use('/casa/assets/css/casa-ie8.css', setHeaders, (req, res) => res.send(casaCssIe8));
64
+ staticRouter.use('/casa/assets', notFoundHandler);
65
+ return staticRouter;
66
+ }
67
+ exports.default = staticRouter;
package/package.json CHANGED
@@ -1,110 +1,69 @@
1
1
  {
2
2
  "name": "@dwp/govuk-casa",
3
- "version": "7.0.6",
4
- "description": "Framework for creating basic GOVUK Collect-And-Submit-Applications",
5
- "main": "casa.js",
3
+ "version": "8.0.0-alpha1",
4
+ "description": "A framework for building GOVUK Collect-And-Submit-Applications",
5
+ "main": "dist/casa.js",
6
+ "module": "dist/mjs/casa.js",
7
+ "exports": {
8
+ "import": "./dist/mjs/esm-wrapper.js",
9
+ "require": "./dist/casa.js"
10
+ },
11
+ "typings": "dist/casa.d.ts",
6
12
  "files": [
7
- "/definitions/**/*",
8
- "/dist/**/*",
9
- "/lib/**/*",
10
- "/locales/**/*",
11
- "/middleware/**/*",
12
- "/test/utils/**/*",
13
- "/src/scss/*",
14
- "/src/browserconfig.xml",
15
- "/views/**/*",
16
- "/index.js",
17
- "/casa.js",
18
- "/**/*.d.ts",
19
- "!/**/*/.DS_Store",
20
- "!/**/*/.gitkeep",
21
- "!/examples/**/*",
22
- "!/test/unit/testdata/**/*"
13
+ "dist/**/*",
14
+ "locales/**/*",
15
+ "views/**/*"
23
16
  ],
24
- "engines": {
25
- "node": ">=14.0.0 <17.0.0"
26
- },
27
- "repository": {
28
- "type": "git",
29
- "url": "git@github.com:dwp/govuk-casa.git"
17
+ "scripts": {
18
+ "test": "mocha './tests/**/*.test.js'",
19
+ "test:e2e": "spiderplan --worker-init ./tests/e2e/worker-init.js --language en ./tests/e2e/personas/**/*.yaml",
20
+ "build": "npm run build:prepare && npm run build:sources && npm run build:css-assets",
21
+ "build:prepare": "rm -rf dist/* && mkdir -p dist/assets/js/ && mkdir -p dist/assets/css/",
22
+ "build:sources": "tsc -p tsconfig-cjs.json && ./scripts/fixup.sh",
23
+ "build:css-assets": "node scripts/compile-sass.js",
24
+ "prepare": "npm run build"
30
25
  },
26
+ "keywords": [],
27
+ "author": "DWP Digital",
28
+ "license": "ISC",
29
+ "type": "module",
31
30
  "dependencies": {
32
- "body-parser": "1.19.0",
33
- "colors": "1.4.0",
31
+ "cookie-parser": "1.4.5",
34
32
  "csurf": "1.11.0",
35
33
  "debug": "4.3.2",
36
- "dot-object": "2.1.4",
37
- "fast-copy": "2.1.1",
38
- "fs-extra": "10.0.0",
39
- "govuk-frontend": "3.13.1",
40
- "govuk_template_jinja": "0.26.0",
34
+ "deepmerge": "4.2.2",
35
+ "express": "4.17.1",
36
+ "express-session": "1.17.2",
37
+ "govuk-frontend": "3.14.0",
41
38
  "graphlib": "2.1.8",
42
- "klaw-sync": "6.0.0",
43
- "lodash.merge": "4.6.2",
39
+ "helmet": "4.6.0",
40
+ "i18next": "21.2.4",
41
+ "i18next-http-middleware": "3.1.4",
42
+ "js-yaml": "4.1.0",
43
+ "lodash": "4.17.21",
44
44
  "luxon": "2.0.2",
45
45
  "nunjucks": "3.2.3",
46
- "serve-favicon": "2.5.0",
47
- "uid-safe": "2.1.5",
48
46
  "uuid": "8.3.2",
49
- "validator": "13.6.0"
47
+ "validator": "^13.6.0"
50
48
  },
51
49
  "devDependencies": {
52
- "@commitlint/cli": "13.2.0",
53
- "@commitlint/config-conventional": "13.2.0",
54
- "@commitlint/travis-cli": "13.2.0",
50
+ "@babel/core": "7.15.8",
51
+ "@babel/eslint-parser": "7.15.8",
52
+ "@babel/preset-env": "7.15.8",
53
+ "@dwp/casa-spiderplan": "1.0.0",
55
54
  "@dwp/commitlint-config-base": "1.2.0",
56
55
  "@dwp/eslint-config-base": "5.0.1",
57
- "@stryker-mutator/core": "5.4.0",
58
- "@stryker-mutator/html-reporter": "3.1.0",
59
- "@stryker-mutator/javascript-mutator": "4.0.0",
60
- "@stryker-mutator/mocha-framework": "4.0.0",
61
- "@stryker-mutator/mocha-runner": "5.4.0",
62
- "autocannon": "7.4.0",
56
+ "@types/express": "4.17.13",
57
+ "@types/node": "16.10.2",
58
+ "babel-eslint": "10.1.0",
63
59
  "chai": "4.3.4",
64
- "chai-as-promised": "7.1.1",
65
- "chai-http": "4.3.0",
66
- "cheerio": "1.0.0-rc.10",
67
- "conventional-changelog-cli": "2.1.1",
60
+ "commitlint": "13.2.0",
68
61
  "eslint": "7.32.0",
69
62
  "eslint-plugin-no-unsafe-regex": "1.0.0",
70
63
  "eslint-plugin-sonarjs": "0.10.0",
71
- "express": "4.17.1",
72
- "express-session": "1.17.2",
73
64
  "husky": "7.0.2",
74
- "jsdom": "17.0.0",
75
- "minimatch": "3.0.4",
76
65
  "mocha": "9.1.2",
77
- "nyc": "15.1.0",
78
- "proxyquire": "2.1.3",
79
66
  "sass": "1.42.1",
80
- "sinon": "11.1.2",
81
- "sinon-chai": "3.7.0",
82
- "supertest": "6.1.6",
83
- "uglify-js": "3.14.2",
84
- "yargs": "17.2.1"
85
- },
86
- "peerDependencies": {
87
- "express": "4.x",
88
- "express-session": "1.x"
89
- },
90
- "scripts": {
91
- "pipeline": "npm test && npm run compliance && npm run quality && npm run security:vulnerable-packages && (npm outdated || true)",
92
- "compliance": "npm run compliance:lint",
93
- "compliance:lint": "eslint .",
94
- "test": "npm run test:unit --silent && npm run test:integration --silent",
95
- "test:unit": "mocha -R spec \"./test/unit/**/*.test.js\"",
96
- "test:integration": "mocha -R spec \"./test/integration/**/*.test.js\"",
97
- "test:performance": "node ./test/performance/plan.test.js",
98
- "quality": "npm run quality:coverage",
99
- "quality:coverage": "nyc npm test",
100
- "quality:mutation": "stryker run",
101
- "security": "npm run security:vulnerable-packages",
102
- "security:vulnerable-packages": "npm audit --production --registry=https://registry.npmjs.org --json | node -e 'a=JSON.parse(fs.readFileSync(\"/dev/stdin\",\"utf-8\")).metadata.vulnerabilities;process.exit(a.high+a.critical);'",
103
- "package:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
104
- "compile-static-assets": "node ./scripts/compile-sass.js && node ./scripts/compile-js.js",
105
- "prepare": "npm run compile-static-assets --silent; husky install",
106
- "upgrade-deps": "OD=$(npm outdated --long --parseable); echo \"$OD\" | grep ':devDependencies:' | awk -F: '{ print $4 }' | xargs npm i -DE; echo \"$OD\" | grep ':dependencies:' | awk -F: '{ print $4 }' | xargs npm i -E"
107
- },
108
- "author": "DWP <open-source@engineering.digital.dwp.gov.uk>",
109
- "license": "ISC"
67
+ "typescript": "4.4.3"
68
+ }
110
69
  }
@@ -16,6 +16,7 @@
16
16
  id: params.id if params.id else 'f-' + params.name + '-wrapper' | safe
17
17
  }) %}
18
18
 
19
+
19
20
  {# Add checked flag to chosen inputs #}
20
21
  {% set mergedItems = [] %}
21
22
  {% for item in params.items %}
@@ -30,6 +31,7 @@
30
31
  {% set mergedItems = (mergedItems.push(item), mergedItems) %}
31
32
  {% endfor %}
32
33
 
34
+
33
35
  {# Merge parameters #}
34
36
  {% set mergedParams = mergeObjects(params, {
35
37
  name: fieldName,
@@ -43,11 +45,12 @@
43
45
 
44
46
  {# Ensure that the first item has the id matching `f-<name>` in order for error summary linkage to work #}
45
47
  {% if not mergedParams.items[0].id %}
46
- {% set mergedParams = mergeObjectsDeep(mergedParams, {
48
+ {% set mergedParams = mergeObjects(mergedParams, {
47
49
  items: [{
48
50
  id: 'f-' + params.name
49
51
  }]
50
52
  }) %}
51
53
  {% endif %}
52
54
 
55
+
53
56
  {{ govukCheckboxes(mergedParams) }}