@dwp/govuk-casa 7.0.6 → 8.0.0-beta1

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 (228) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +22 -17
  3. package/dist/{casa → assets}/css/casa-ie8.css +1 -1
  4. package/dist/assets/css/casa.css +1 -0
  5. package/dist/casa.d.ts +11 -0
  6. package/dist/casa.js +46 -0
  7. package/dist/lib/CasaTemplateLoader.d.ts +29 -0
  8. package/dist/lib/CasaTemplateLoader.js +74 -0
  9. package/dist/lib/JourneyContext.d.ts +297 -0
  10. package/dist/lib/JourneyContext.js +581 -0
  11. package/dist/lib/MutableRouter.d.ts +155 -0
  12. package/dist/lib/MutableRouter.js +277 -0
  13. package/dist/lib/Plan.d.ts +154 -0
  14. package/dist/lib/Plan.js +442 -0
  15. package/dist/lib/ValidationError.d.ts +74 -0
  16. package/dist/lib/ValidationError.js +159 -0
  17. package/dist/lib/ValidatorFactory.d.ts +83 -0
  18. package/dist/lib/ValidatorFactory.js +106 -0
  19. package/dist/lib/configuration-ingestor.d.ts +262 -0
  20. package/dist/lib/configuration-ingestor.js +490 -0
  21. package/dist/lib/configure.d.ts +90 -0
  22. package/dist/lib/configure.js +192 -0
  23. package/dist/lib/dirname.cjs +1 -0
  24. package/dist/lib/dirname.d.cts +2 -0
  25. package/dist/lib/end-session.d.ts +13 -0
  26. package/dist/lib/end-session.js +43 -0
  27. package/dist/lib/field.d.ts +77 -0
  28. package/dist/lib/field.js +255 -0
  29. package/dist/lib/index.d.ts +14 -0
  30. package/dist/lib/index.js +54 -0
  31. package/dist/lib/logger.d.ts +9 -0
  32. package/dist/lib/logger.js +18 -0
  33. package/dist/lib/nunjucks-filters.d.ts +26 -0
  34. package/dist/lib/nunjucks-filters.js +90 -0
  35. package/dist/lib/nunjucks.d.ts +23 -0
  36. package/dist/lib/nunjucks.js +49 -0
  37. package/dist/lib/utils.d.ts +48 -0
  38. package/dist/lib/utils.js +111 -0
  39. package/dist/lib/validators/dateObject.d.ts +4 -0
  40. package/dist/lib/validators/dateObject.js +135 -0
  41. package/dist/lib/validators/email.d.ts +4 -0
  42. package/dist/lib/validators/email.js +46 -0
  43. package/dist/lib/validators/inArray.d.ts +4 -0
  44. package/dist/lib/validators/inArray.js +60 -0
  45. package/dist/lib/validators/index.d.ts +21 -0
  46. package/dist/lib/validators/index.js +47 -0
  47. package/dist/lib/validators/nino.d.ts +4 -0
  48. package/dist/lib/validators/nino.js +46 -0
  49. package/dist/lib/validators/postalAddressObject.d.ts +4 -0
  50. package/dist/lib/validators/postalAddressObject.js +123 -0
  51. package/dist/lib/validators/regex.d.ts +4 -0
  52. package/dist/lib/validators/regex.js +40 -0
  53. package/dist/lib/validators/required.d.ts +4 -0
  54. package/dist/lib/validators/required.js +56 -0
  55. package/dist/lib/validators/strlen.d.ts +4 -0
  56. package/dist/lib/validators/strlen.js +51 -0
  57. package/dist/lib/validators/wordCount.d.ts +5 -0
  58. package/dist/lib/validators/wordCount.js +54 -0
  59. package/dist/lib/waypoint-url.d.ts +23 -0
  60. package/dist/lib/waypoint-url.js +52 -0
  61. package/dist/middleware/body-parser.d.ts +1 -0
  62. package/dist/middleware/body-parser.js +24 -0
  63. package/dist/middleware/csrf.d.ts +1 -0
  64. package/dist/middleware/csrf.js +31 -0
  65. package/dist/middleware/data.d.ts +5 -0
  66. package/dist/middleware/data.js +53 -0
  67. package/dist/middleware/dirname.cjs +1 -0
  68. package/dist/middleware/dirname.d.cts +2 -0
  69. package/dist/middleware/gather-fields.d.ts +6 -0
  70. package/dist/middleware/gather-fields.js +48 -0
  71. package/dist/middleware/i18n.d.ts +4 -0
  72. package/dist/middleware/i18n.js +88 -0
  73. package/dist/middleware/post.d.ts +3 -0
  74. package/dist/middleware/post.js +57 -0
  75. package/dist/middleware/pre.d.ts +3 -0
  76. package/dist/middleware/pre.js +51 -0
  77. package/dist/middleware/progress-journey.d.ts +6 -0
  78. package/dist/middleware/progress-journey.js +80 -0
  79. package/dist/middleware/sanitise-fields.d.ts +5 -0
  80. package/dist/middleware/sanitise-fields.js +53 -0
  81. package/dist/middleware/session.d.ts +11 -0
  82. package/dist/middleware/session.js +121 -0
  83. package/dist/middleware/skip-waypoint.d.ts +5 -0
  84. package/dist/middleware/skip-waypoint.js +43 -0
  85. package/dist/middleware/steer-journey.d.ts +7 -0
  86. package/dist/middleware/steer-journey.js +62 -0
  87. package/dist/middleware/validate-fields.d.ts +7 -0
  88. package/dist/middleware/validate-fields.js +67 -0
  89. package/dist/mjs/esm-wrapper.js +11 -0
  90. package/dist/mjs/package.json +3 -0
  91. package/dist/package.json +3 -0
  92. package/dist/routes/ancillary.d.ts +11 -0
  93. package/dist/routes/ancillary.js +27 -0
  94. package/dist/routes/dirname.cjs +1 -0
  95. package/dist/routes/dirname.d.cts +2 -0
  96. package/dist/routes/journey.d.ts +8 -0
  97. package/dist/routes/journey.js +127 -0
  98. package/dist/routes/static.d.ts +26 -0
  99. package/dist/routes/static.js +68 -0
  100. package/package.json +64 -89
  101. package/views/casa/components/checkboxes/template.njk +4 -1
  102. package/views/casa/components/date-input/template.njk +3 -3
  103. package/views/casa/components/journey-form/README.md +3 -1
  104. package/views/casa/components/journey-form/template.njk +1 -1
  105. package/views/casa/components/postal-address-object/template.njk +5 -5
  106. package/views/casa/components/radios/template.njk +1 -1
  107. package/views/casa/errors/static.njk +11 -0
  108. package/views/casa/layouts/journey.njk +26 -9
  109. package/views/casa/layouts/main.njk +7 -20
  110. package/views/casa/partials/scripts.njk +8 -3
  111. package/views/casa/partials/styles.njk +2 -2
  112. package/casa.js +0 -208
  113. package/definitions/review-page.js +0 -60
  114. package/dist/casa/css/casa.css +0 -1
  115. package/dist/casa/js/casa.js +0 -1
  116. package/index.d.ts +0 -121
  117. package/lib/ConfigIngestor.js +0 -588
  118. package/lib/GatherModifier.js +0 -14
  119. package/lib/I18n.js +0 -160
  120. package/lib/JourneyContext.d.ts +0 -97
  121. package/lib/JourneyContext.js +0 -552
  122. package/lib/JourneyMap.js +0 -233
  123. package/lib/JourneyRoad.js +0 -330
  124. package/lib/Logger.js +0 -59
  125. package/lib/PageDictionary.d.ts +0 -11
  126. package/lib/PageDirectory.js +0 -77
  127. package/lib/Plan.js +0 -423
  128. package/lib/RoadConverter.js +0 -153
  129. package/lib/UserJourney.js +0 -8
  130. package/lib/Util.js +0 -227
  131. package/lib/Validation.js +0 -20
  132. package/lib/bootstrap/end-session.js +0 -44
  133. package/lib/bootstrap/load-definitions.js +0 -64
  134. package/lib/commonBodyParser.js +0 -15
  135. package/lib/enums.js +0 -6
  136. package/lib/gather-modifiers/index.js +0 -7
  137. package/lib/gather-modifiers/trimPostalAddressObject.js +0 -75
  138. package/lib/gather-modifiers/trimWhitespace.js +0 -16
  139. package/lib/utils/createGetRequest.d.ts +0 -5
  140. package/lib/utils/createGetRequest.js +0 -59
  141. package/lib/utils/index.js +0 -11
  142. package/lib/utils/parseRequest.d.ts +0 -5
  143. package/lib/utils/parseRequest.js +0 -72
  144. package/lib/utils/sanitise.js +0 -74
  145. package/lib/utils/validate.js +0 -32
  146. package/lib/validation/ArrayObjectField.js +0 -49
  147. package/lib/validation/ObjectField.js +0 -53
  148. package/lib/validation/SimpleField.d.ts +0 -11
  149. package/lib/validation/SimpleField.js +0 -46
  150. package/lib/validation/ValidationError.d.ts +0 -14
  151. package/lib/validation/ValidationError.js +0 -170
  152. package/lib/validation/ValidatorFactory.d.ts +0 -32
  153. package/lib/validation/ValidatorFactory.js +0 -91
  154. package/lib/validation/index.js +0 -22
  155. package/lib/validation/processor/flattenErrorArray.js +0 -24
  156. package/lib/validation/processor/queue.js +0 -214
  157. package/lib/validation/processor.js +0 -84
  158. package/lib/validation/rules/README.md +0 -3
  159. package/lib/validation/rules/ValidationRules.d.ts +0 -22
  160. package/lib/validation/rules/dateObject.js +0 -156
  161. package/lib/validation/rules/email.js +0 -44
  162. package/lib/validation/rules/inArray.js +0 -61
  163. package/lib/validation/rules/index.js +0 -23
  164. package/lib/validation/rules/nino.js +0 -48
  165. package/lib/validation/rules/optional.js +0 -14
  166. package/lib/validation/rules/postalAddressObject.js +0 -142
  167. package/lib/validation/rules/regex.js +0 -39
  168. package/lib/validation/rules/required.js +0 -57
  169. package/lib/validation/rules/strlen.js +0 -57
  170. package/lib/validation/rules/wordCount.js +0 -61
  171. package/lib/view-filters/formatDateObject.js +0 -35
  172. package/lib/view-filters/includes.js +0 -10
  173. package/lib/view-filters/index.js +0 -23
  174. package/lib/view-filters/mergeObjectsDeep.js +0 -21
  175. package/lib/view-filters/renderAsAttributes.js +0 -33
  176. package/middleware/errors/404.js +0 -12
  177. package/middleware/errors/catch-all.js +0 -27
  178. package/middleware/errors/index.js +0 -9
  179. package/middleware/headers/config-defaults.js +0 -57
  180. package/middleware/headers/headers.js +0 -40
  181. package/middleware/headers/index.js +0 -9
  182. package/middleware/i18n/i18n.js +0 -56
  183. package/middleware/i18n/index.js +0 -16
  184. package/middleware/index.js +0 -55
  185. package/middleware/mount/index.js +0 -9
  186. package/middleware/mount/mount.js +0 -10
  187. package/middleware/nunjucks/environment.js +0 -57
  188. package/middleware/nunjucks/index.js +0 -8
  189. package/middleware/page/csrf.js +0 -37
  190. package/middleware/page/edit-mode.js +0 -52
  191. package/middleware/page/gather.js +0 -75
  192. package/middleware/page/index.js +0 -103
  193. package/middleware/page/journey-continue.js +0 -157
  194. package/middleware/page/journey-rails.js +0 -102
  195. package/middleware/page/prepare-request.js +0 -77
  196. package/middleware/page/render.js +0 -75
  197. package/middleware/page/skip.js +0 -72
  198. package/middleware/page/utils.js +0 -206
  199. package/middleware/page/validate.js +0 -67
  200. package/middleware/session/expiry.js +0 -95
  201. package/middleware/session/genid.js +0 -18
  202. package/middleware/session/index.js +0 -18
  203. package/middleware/session/init.js +0 -25
  204. package/middleware/session/seed.js +0 -50
  205. package/middleware/session/timeout.js +0 -5
  206. package/middleware/static/asset-versions.js +0 -23
  207. package/middleware/static/index.js +0 -104
  208. package/middleware/static/prepare-assets.js +0 -51
  209. package/middleware/static/serve-assets.js +0 -58
  210. package/middleware/variables/index.js +0 -12
  211. package/middleware/variables/variables.js +0 -35
  212. package/src/browserconfig.xml +0 -5
  213. package/src/js/casa.js +0 -132
  214. package/src/scss/_casaElements.scss +0 -11
  215. package/src/scss/_casaGovukTemplateJinjaPolyfill.scss +0 -39
  216. package/src/scss/_casaMountUrl.scss +0 -8
  217. package/src/scss/casa-ie8.scss +0 -3
  218. package/src/scss/casa.scss +0 -14
  219. package/test/unit/templates/README.md +0 -5
  220. package/test/utils/BaseTestWaypoint.js +0 -106
  221. package/test/utils/concatWaypoints.js +0 -26
  222. package/test/utils/index.js +0 -6
  223. package/test/utils/testTraversal.js +0 -90
  224. package/views/casa/partials/cookie_message.njk +0 -3
  225. package/views/casa/partials/phase_banner_alpha.njk +0 -8
  226. package/views/casa/partials/phase_banner_beta.njk +0 -8
  227. package/views/casa/review/page-block.njk +0 -8
  228. package/views/casa/review/review.njk +0 -47
package/lib/Plan.js DELETED
@@ -1,423 +0,0 @@
1
- const { Graph } = require('graphlib');
2
- const JourneyContext = require('./JourneyContext.js');
3
- const logger = require('./Logger.js')('class.Plan');
4
-
5
- /**
6
- * Will check if the source waypoint has specifically passed validation, i.e
7
- * there is a "null" validation entry for the route source.
8
- *
9
- * @param {object} r Route meta.
10
- * @param {JourneyContext} context Journey Context.
11
- * @returns {boolean} Condition result.
12
- */
13
- function defaultNextFollow(r, context) {
14
- const { validation: v = {} } = context.toObject();
15
- return Object.prototype.hasOwnProperty.call(v, r.source) && v[r.source] === null;
16
- }
17
-
18
- /**
19
- * Will check if the target waypoint (the one we're moving back to) has
20
- * specifically passed validation.
21
- *
22
- * @param {object} r Route meta.
23
- * @param {JourneyContext} context Journey context.
24
- * @returns {boolean} Condition result.
25
- */
26
- function defaultPrevFollow(r, context) {
27
- const { validation: v = {} } = context.toObject();
28
- return Object.prototype.hasOwnProperty.call(v, r.target) && v[r.target] === null;
29
- }
30
-
31
- function validateWaypointId(val) {
32
- if (typeof val !== 'string') {
33
- throw new TypeError(`Expected waypoint id to be a string, got ${typeof val}`);
34
- }
35
- }
36
-
37
- function validateRouteName(val) {
38
- if (typeof val !== 'string') {
39
- throw new TypeError(`Expected route name to be a string, got ${typeof val}`);
40
- } else if (!['next', 'prev', 'origin'].includes(val)) {
41
- throw new ReferenceError(`Expected route name to be one of next, prev or origin. Got ${val}`)
42
- }
43
- }
44
-
45
- function validateRouteCondition(val) {
46
- if (!(val instanceof Function)) {
47
- throw new TypeError(`Expected route condition to be a function, got ${typeof val}`);
48
- }
49
- }
50
-
51
- /**
52
- * Creates a user friendly route structure from a given graph edge which will
53
- * be used in userland. This is the object that will be passed into follow
54
- * functions too as the "route" parameter.
55
- *
56
- * @param {object} dgraph Directed graph instance.
57
- * @param {object} edge Graph edge object.
58
- * @returns {object} Route.
59
- */
60
- const makeRouteObject = (dgraph, edge) => {
61
- const label = dgraph.edge(edge) || {
62
- vorigin: undefined,
63
- worigin: undefined,
64
- };
65
- return {
66
- source: edge.v,
67
- target: edge.w,
68
- name: edge.name,
69
- label: {
70
- sourceOrigin: label.vorigin,
71
- targetOrigin: label.worigin,
72
- },
73
- };
74
- };
75
-
76
- const priv = new WeakMap();
77
-
78
- class Plan {
79
- constructor(opts = {}) {
80
- // This is our directed, multigraph representation
81
- const dgraph = new Graph({
82
- directed: true,
83
- multigraph: true,
84
- compound: false,
85
- });
86
-
87
- // Add "__origin__" node that acts as the source for all "origin" routes
88
- dgraph.setNode('__origin__');
89
-
90
- // Gather options
91
- const options = Object.assign(Object.create(null), {
92
- // When true, the validation state of the source node must be `null` (i.e.
93
- // no validation errors) before any custom route conditions are evaluated.
94
- validateBeforeRouteCondition: true,
95
- }, opts);
96
- Object.freeze(options);
97
-
98
- priv.set(this, {
99
- dgraph,
100
- follows: {
101
- next: {},
102
- prev: {},
103
- origin: {},
104
- },
105
- options,
106
- });
107
- }
108
-
109
- getOptions() {
110
- return priv.get(this).options;
111
- }
112
-
113
- getWaypoints() {
114
- return priv.get(this).dgraph.nodes();
115
- }
116
-
117
- containsWaypoint(waypoint) {
118
- return this.getWaypoints().includes(waypoint);
119
- }
120
-
121
- getRoutes() {
122
- const self = priv.get(this);
123
- return self.dgraph.edges().map((edge) => makeRouteObject(self.dgraph, edge));
124
- }
125
-
126
- getRouteCondition(src, tgt, name) {
127
- return priv.get(this).follows[name][`${src}/${tgt}`];
128
- }
129
-
130
- /**
131
- * Return all outward routes (out-edges) from the given waypoint, to the
132
- * optional target waypoint.
133
- *
134
- * @param {string} src Source waypoint.
135
- * @param {string} tgt Target waypoint (optional).
136
- * @returns {Array<object>} Route objects found.
137
- */
138
- getOutwardRoutes(src, tgt = null) {
139
- const self = priv.get(this);
140
- return self.dgraph.outEdges(src, tgt).map((e) => makeRouteObject(self.dgraph, e));
141
- }
142
-
143
- /**
144
- * Return all outward routes (out-edges) from the given waypoint, to the
145
- * optional target waypoint, matching the "prev" name.
146
- *
147
- * @param {string} src Source waypoint.
148
- * @param {string} tgt Target waypoint (optional).
149
- * @returns {Array<object>} Route objects found.
150
- */
151
- getPrevOutwardRoutes(src, tgt = null) {
152
- return this.getOutwardRoutes(src, tgt).filter((r) => r.name === 'prev');
153
- }
154
-
155
- /**
156
- * Get info about all the defined origins.
157
- *
158
- * Each origin is returned as an object in the format:
159
- * {
160
- * originId: '<unique-id-of-the-origin>',
161
- * waypoint: '<the-waypoint-at-which-traversals-start>',
162
- * }
163
- *
164
- * @returns {Array<object>} Origins
165
- */
166
- getOrigins() {
167
- const self = priv.get(this);
168
- return self.dgraph.outEdges('__origin__').map((e) => ({
169
- originId: self.dgraph.node(e.w).originId,
170
- waypoint: e.w,
171
- }));
172
- }
173
-
174
- addOrigin(originId, waypoint, follow) {
175
- // Set up a unique route from __origin__ to this waypoint, and label with
176
- // the origin ID
177
- priv.get(this).dgraph.setNode(waypoint, { originId });
178
- this.setNamedRoute('__origin__', waypoint, 'origin', follow || (() => (true)));
179
- }
180
-
181
- addSequence(...waypoints) {
182
- // Setup simple double routes (next/prev) between all waypoints in this list
183
- for (let i = 0, l = waypoints.length - 1; i < l; i += 1) {
184
- this.setRoute(waypoints[i], waypoints[i + 1]);
185
- }
186
- }
187
-
188
- setNextRoute(src, tgt, follow) {
189
- return this.setNamedRoute(src, tgt, 'next', follow);
190
- }
191
-
192
- setPrevRoute(src, tgt, follow) {
193
- return this.setNamedRoute(src, tgt, 'prev', follow);
194
- }
195
-
196
- /**
197
- * Adds both a "next" and "prev" route between the two waypoints.
198
- *
199
- * By default, the "prev" route will use the same "follow" test as the "next"
200
- * route. This makes sense in that in order to get the target, the test must
201
- * have been true, and so to reverse the direction we also need that same test
202
- * to be true.
203
- *
204
- * @param {string} src Source waypoint.
205
- * @param {string} tgt Target waypoint.
206
- * @param {Function} followNext Follow test function.
207
- * @param {Function} followPrev Follow test function.
208
- * @returns {Plan} Self.
209
- */
210
- setRoute(src, tgt, followNext = undefined, followPrev = undefined) {
211
- this.setNamedRoute(src, tgt, 'next', followNext);
212
- this.setNamedRoute(tgt, src, 'prev', followPrev || followNext);
213
- return this;
214
- }
215
-
216
- /**
217
- * Create a named route between two waypoints, and give that route a function
218
- * that determine whether it should be followed during traversal operations.
219
- * Note that the source waypoint must be in a successful validation state
220
- * to be considered for traversal, regardless of what the custom function
221
- * determines.
222
- *
223
- * You can also inform how the plan will be traversed by including origin IDs
224
- * in the src/tgt waypoints. For example:
225
- *
226
- * setNamedRoute("originA:hello", "originB:world");
227
- *
228
- * Note that if you specify an origin in one waypoint, you must specify one in
229
- * the other waypoint too.
230
- *
231
- * @param {string} srcId Source waypoint.
232
- * @param {string} tgtId Target waypoint.
233
- * @param {string} name Name of the route (must be unique for this waypoint pairing).
234
- * @param {Function} follow Test function to determine if route can be followed.
235
- * @returns {Plan} Chain.
236
- */
237
- setNamedRoute(srcId, tgtId, name, follow) {
238
- const self = priv.get(this);
239
-
240
- // Validate
241
- validateWaypointId(srcId);
242
- validateWaypointId(tgtId);
243
- validateRouteName(name);
244
- if (follow !== undefined) {
245
- validateRouteCondition(follow);
246
- }
247
-
248
- // Pick out the origin ids from src/tgt waypoint ids
249
- const src = srcId.indexOf(':') > -1 ? srcId.split(':')[1] : srcId;
250
- const vorigin = srcId.indexOf(':') > -1 ? srcId.split(':')[0] : self.guid;
251
- const tgt = tgtId.indexOf(':') > -1 ? tgtId.split(':')[1] : tgtId;
252
- const worigin = tgtId.indexOf(':') > -1 ? tgtId.split(':')[0] : self.guid;
253
-
254
- // Get routing function name to label edge
255
- const label = follow && follow.name;
256
-
257
- // Warn if we're overwriting an existing edge on the same name
258
- if (self.dgraph.hasEdge(src, tgt, name)) {
259
- logger.warn('Setting a route that already exists (%s, %s, %s). Will be overridden', src, tgt, name);
260
- }
261
- self.dgraph.setEdge(src, tgt, { vorigin, worigin, label }, name);
262
-
263
- // Determine which follow function to use
264
- let followFunc;
265
- if (follow) {
266
- if (!self.options.validateBeforeRouteCondition) {
267
- followFunc = follow;
268
- } else if (name === 'next') {
269
- // Retain the original function name of route condition
270
- followFunc = {
271
- [follow.name]: (r, c) => (defaultNextFollow(r, c) && follow(r, c)),
272
- }[follow.name];
273
- } else {
274
- // Retain the original function name of route condition
275
- followFunc = {
276
- [follow.name]: (r, c) => (defaultPrevFollow(r, c) && follow(r, c)),
277
- }[follow.name];
278
- }
279
- } else if (name === 'next') {
280
- followFunc = defaultNextFollow;
281
- } else {
282
- followFunc = defaultPrevFollow;
283
- }
284
- self.follows[name][`${src}/${tgt}`] = followFunc;
285
-
286
- return this;
287
- }
288
-
289
- /**
290
- * This is a convenience method for traversing all "next" routes, and returning
291
- * the IDs of all waypoints visited along the way.
292
- *
293
- * @param {JourneyContext} context Journey Context.
294
- * @param {object} options Options.
295
- * @returns {Array<string>} List of traversed waypoints.
296
- */
297
- traverse(context, options = {}) {
298
- return this.traverseNextRoutes(context, options).map((e) => e.source);
299
- }
300
-
301
- traverseNextRoutes(context, options = {}) {
302
- return this.traverseRoutes(context, { ...options, routeName: 'next' })
303
- }
304
-
305
- traversePrevRoutes(context, options = {}) {
306
- return this.traverseRoutes(context, { ...options, routeName: 'prev' })
307
- }
308
-
309
- /**
310
- * Traverse through the plan from a particular starting waypoint (usually an
311
- * origin waypoint, but not necessarily). This is a non-exhaustive Graph
312
- * Exploration.
313
- *
314
- * The last route in the list will contain the source of the last waypoint that
315
- * can be reached, i.e. The waypoint that has no further satisfiable out-edges.
316
- *
317
- * If a cyclical set of routes are encountered, traversal will stop after
318
- * reaching the first repeated waypoint.
319
- *
320
- * Options:
321
- * string startWaypoint = Waypoint from which to start traversal
322
- * string routeName = Follow routes matching this name (next | prev)
323
- * Map history = Used to detect loops in traversal (internal use)
324
- * function stopCondition = Condition that, if true, will stop traversal (useful for performance)
325
- *
326
- * @param {JourneyContext} context Journey context
327
- * @param {object} options Options
328
- * @returns {Array<object>} Routes that were traversed
329
- * @throws {TypeError} When context is not a JourneyContext
330
- */
331
- traverseRoutes(context, options = {}) {
332
- if (!(context instanceof JourneyContext)) {
333
- throw new TypeError(`Expected context to be an instance of JourneyContext, got ${typeof context}`);
334
- }
335
-
336
- const self = priv.get(this);
337
- const {
338
- startWaypoint = (this.getOrigins()[0] || {}).waypoint,
339
- stopCondition = () => (false),
340
- routeName,
341
- } = options;
342
-
343
- if (!self.dgraph.hasNode(startWaypoint)) {
344
- throw new ReferenceError(`Plan does not contain waypoint '${startWaypoint}'`);
345
- }
346
-
347
- if (routeName === undefined) {
348
- throw new ReferenceError('Route name must be provided');
349
- }
350
-
351
- const history = new Map();
352
-
353
- const traverse = (startWP) => {
354
- const target = self.dgraph.outEdges(startWP).filter((e) => {
355
- if (e.name !== routeName) {
356
- return false;
357
- }
358
- const route = makeRouteObject(self.dgraph, e);
359
- try {
360
- return self.follows[routeName][`${e.v}/${e.w}`](route, context);
361
- } catch (ex) {
362
- logger.warn('Route follow function threw an exception, "%s" (%s)', ex.message, `${e.v}/${e.w}`);
363
- return false;
364
- }
365
- });
366
-
367
- if (target.length === 1) {
368
- const route = makeRouteObject(self.dgraph, target[0]);
369
- const routeHash = `${route.name}/${route.source}/${route.target}`;
370
-
371
- if (stopCondition(route)) {
372
- return [route];
373
- }
374
- if (!history.has(routeHash)) {
375
- history.set(routeHash, null);
376
- const traversed = traverse(target[0].w);
377
- const totalTrav = traversed.length;
378
- const results = new Array(totalTrav + 1);
379
- results[0] = route;
380
-
381
- for (let i = 0; i < totalTrav; i++) {
382
- results[i + 1] = traversed[i];
383
- }
384
-
385
- return results;
386
- }
387
- logger.debug('Encountered loop (%s). Stopping traversal.', `${route.source} -> ${route.target}`);
388
- }
389
-
390
- if (target.length > 1) {
391
- const satisifed = target.map((t) => `${t.v} -> ${t.w}`);
392
- logger.warn(
393
- `Multiple routes were satisfied for "${routeName}" route (${satisifed.join(' / ')}). `
394
- + `Cannot determine which to use so stopping traversal at "${startWP}".`,
395
- )
396
- }
397
-
398
- return [makeRouteObject(self.dgraph, {
399
- v: startWP,
400
- w: null,
401
- name: routeName,
402
- label: {
403
- vorigin: undefined,
404
- worigin: undefined,
405
- },
406
- })];
407
- };
408
-
409
- return traverse(startWaypoint);
410
- }
411
-
412
- /**
413
- * Get raw graph data structure. This can be used with other libraries to
414
- * generate graph visualisations, for example.
415
- *
416
- * @returns {graphlib.Graph} Graph data structure.
417
- */
418
- getGraphStructure() {
419
- return priv.get(this).dgraph;
420
- }
421
- }
422
-
423
- module.exports = Plan;
@@ -1,153 +0,0 @@
1
- const JourneyRoad = require('./JourneyRoad.js');
2
- const Plan = require('./Plan.js');
3
- const logger = require('./Logger')('RoadConverter');
4
-
5
- class RoadConverter {
6
- constructor(plan, road) {
7
- if (!(plan instanceof Plan)) {
8
- throw new TypeError('plan must be instance of Plan');
9
- }
10
- if (!(road instanceof JourneyRoad)) {
11
- throw new TypeError('road must be instance of JourneyRoad');
12
- }
13
- logger.info('Starting new Road...');
14
- this.plan = plan;
15
- this.road = road;
16
- this.pois = this.road.getPOIs();
17
- }
18
-
19
- hasRoute(source, target) {
20
- if (typeof source !== 'string') {
21
- throw new TypeError('source must be a string');
22
- }
23
- if (typeof target !== 'string') {
24
- throw new TypeError('target must be a string');
25
- }
26
- return this.plan.getRoutes()
27
- .filter((route) => route.source === source && route.target === target).length > 0;
28
- }
29
-
30
- setRoute(source, target, nextCondition, prevCondition) {
31
- if (typeof source !== 'string') {
32
- throw new TypeError('source must be a string');
33
- }
34
- if (typeof target !== 'string') {
35
- throw new TypeError('target must be a string');
36
- }
37
- if (!(typeof nextCondition === 'undefined' || typeof nextCondition === 'function')) {
38
- throw new TypeError('nextCondition must be a function');
39
- }
40
- if (!(typeof prevCondition === 'undefined' || typeof prevCondition === 'function' || prevCondition === null)) {
41
- throw new TypeError('prevCondition must be a function');
42
- }
43
- if (!this.hasRoute(source, target) && (typeof source !== 'undefined' && typeof target !== 'undefined')) {
44
- logger.info(`Setting route: ${source} to ${target} ${typeof nextCondition === 'function' ? '(conditional)' : ''}`);
45
- this.plan.setRoute(source, target, nextCondition, prevCondition);
46
- }
47
- }
48
-
49
- getNextWaypoint(waypoint) {
50
- let nextWaypoint;
51
- let nextWaypointCondition;
52
- if (waypoint.nextWaypoint() && waypoint.nextWaypoint().id !== JourneyRoad.WAYPOINT_FAULT_ID) {
53
- nextWaypoint = waypoint.nextWaypoint();
54
- } else {
55
- const waypointIndex = this.pois.indexOf(waypoint);
56
- if (waypointIndex !== -1) {
57
- nextWaypoint = this.pois[waypointIndex + 1];
58
- }
59
- if (nextWaypoint && nextWaypoint.type === JourneyRoad.POI_WAYPOINT) {
60
- nextWaypointCondition = nextWaypoint.show;
61
- }
62
- }
63
- return {
64
- nextWaypoint,
65
- nextWaypointCondition,
66
- }
67
- }
68
-
69
- static getWaypointFromFork(fork, index = 0) {
70
- return fork.roads && fork.roads[index].getPOIs()[0];
71
- }
72
-
73
- addConditionalRoute(source, target1, target2, positiveCondition) {
74
- this.setRoute(source, target1, (r, c) => positiveCondition(c.data));
75
- this.setRoute(source, target2, (r, c) => !positiveCondition(c.data));
76
- }
77
-
78
- addWaypointRoute(waypoint) {
79
- const { nextWaypoint, nextWaypointCondition } = this.getNextWaypoint(waypoint);
80
- if (nextWaypointCondition) {
81
- const { nextWaypoint: target2 } = this.getNextWaypoint(nextWaypoint);
82
- this.addConditionalRoute(waypoint.id, nextWaypoint.id, target2.id, nextWaypointCondition)
83
- } else if (nextWaypoint && nextWaypoint.type === JourneyRoad.POI_WAYPOINT) {
84
- this.setRoute(waypoint.id, nextWaypoint.id)
85
- }
86
- }
87
-
88
- mergeAlreadyExists(poi) {
89
- return this.plan.getRoutes()
90
- .filter((route) => route.source === poi.nextWaypoint().id && route.name === 'next').length > 0
91
- }
92
-
93
- roadAlreadyFollowed(road) {
94
- if (!(road instanceof JourneyRoad)) {
95
- throw new TypeError('road must be an instance of JourneyRoad');
96
- }
97
- return this.plan.getRoutes()
98
- .filter((route) => route.source === road.getPOIs()[0].id && route.name === 'next').length > 0
99
- }
100
-
101
- processPoi(poi) {
102
- let sourceIndex;
103
- let numOfChoices;
104
- let alreadyMerged;
105
- switch (poi.type) {
106
- case JourneyRoad.POI_WAYPOINT:
107
- this.addWaypointRoute(poi);
108
- break;
109
- case JourneyRoad.POI_FORK:
110
- sourceIndex = this.pois.indexOf(poi) - 1;
111
- numOfChoices = poi.roads.length;
112
- poi.roads.forEach((road, roadIndex) => {
113
- if (sourceIndex > -1) {
114
- const choices = Array(numOfChoices).fill(false);
115
- choices[roadIndex] = true;
116
- this.setRoute(this.pois[sourceIndex].id,
117
- road.getPOIs()[0].id,
118
- (r, c) => poi.test(choices,
119
- c.data), null);
120
- }
121
- const roadAlreadyFollowed = this.roadAlreadyFollowed(road);
122
- if (!roadAlreadyFollowed) {
123
- const roadConversion = new RoadConverter(this.plan, road);
124
- roadConversion.convert();
125
- }
126
- });
127
- break;
128
- case JourneyRoad.POI_MERGE:
129
- alreadyMerged = this.mergeAlreadyExists(poi);
130
- if (!alreadyMerged) {
131
- const startRoadConversion = new RoadConverter(this.plan, poi.road);
132
- startRoadConversion.convert();
133
- }
134
- break;
135
- case JourneyRoad.POI_END:
136
- default:
137
- break;
138
- }
139
- }
140
-
141
- processPois(pois) {
142
- pois.forEach((poi) => {
143
- this.processPoi(poi);
144
- });
145
- }
146
-
147
- convert() {
148
- this.processPois(this.pois);
149
- return this;
150
- }
151
- }
152
-
153
- module.exports = RoadConverter;
@@ -1,8 +0,0 @@
1
- const util = require('util');
2
- const JourneyMap = require('./JourneyMap.js');
3
- const JourneyRoad = require('./JourneyRoad.js');
4
-
5
- module.exports = util.deprecate(() => ({
6
- Map: JourneyMap,
7
- Road: JourneyRoad,
8
- }), '@dwp/govuk-casa/lib/UserJourney should be replaced with "const { Plan } = require(\'@dwp/govuk-casa\')"')();