@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.
- package/CHANGELOG.md +8 -0
- package/README.md +22 -17
- package/dist/{casa → assets}/css/casa-ie8.css +1 -1
- package/dist/assets/css/casa.css +1 -0
- package/dist/casa.d.ts +11 -0
- package/dist/casa.js +46 -0
- package/dist/lib/CasaTemplateLoader.d.ts +29 -0
- package/dist/lib/CasaTemplateLoader.js +74 -0
- package/dist/lib/JourneyContext.d.ts +297 -0
- package/dist/lib/JourneyContext.js +581 -0
- package/dist/lib/MutableRouter.d.ts +155 -0
- package/dist/lib/MutableRouter.js +277 -0
- package/dist/lib/Plan.d.ts +154 -0
- package/dist/lib/Plan.js +442 -0
- package/dist/lib/ValidationError.d.ts +74 -0
- package/dist/lib/ValidationError.js +159 -0
- package/dist/lib/ValidatorFactory.d.ts +83 -0
- package/dist/lib/ValidatorFactory.js +106 -0
- package/dist/lib/configuration-ingestor.d.ts +262 -0
- package/dist/lib/configuration-ingestor.js +490 -0
- package/dist/lib/configure.d.ts +90 -0
- package/dist/lib/configure.js +192 -0
- package/dist/lib/dirname.cjs +1 -0
- package/dist/lib/dirname.d.cts +2 -0
- package/dist/lib/end-session.d.ts +13 -0
- package/dist/lib/end-session.js +43 -0
- package/dist/lib/field.d.ts +77 -0
- package/dist/lib/field.js +255 -0
- package/dist/lib/index.d.ts +14 -0
- package/dist/lib/index.js +54 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +18 -0
- package/dist/lib/nunjucks-filters.d.ts +26 -0
- package/dist/lib/nunjucks-filters.js +90 -0
- package/dist/lib/nunjucks.d.ts +23 -0
- package/dist/lib/nunjucks.js +49 -0
- package/dist/lib/utils.d.ts +48 -0
- package/dist/lib/utils.js +111 -0
- package/dist/lib/validators/dateObject.d.ts +4 -0
- package/dist/lib/validators/dateObject.js +135 -0
- package/dist/lib/validators/email.d.ts +4 -0
- package/dist/lib/validators/email.js +46 -0
- package/dist/lib/validators/inArray.d.ts +4 -0
- package/dist/lib/validators/inArray.js +60 -0
- package/dist/lib/validators/index.d.ts +21 -0
- package/dist/lib/validators/index.js +47 -0
- package/dist/lib/validators/nino.d.ts +4 -0
- package/dist/lib/validators/nino.js +46 -0
- package/dist/lib/validators/postalAddressObject.d.ts +4 -0
- package/dist/lib/validators/postalAddressObject.js +123 -0
- package/dist/lib/validators/regex.d.ts +4 -0
- package/dist/lib/validators/regex.js +40 -0
- package/dist/lib/validators/required.d.ts +4 -0
- package/dist/lib/validators/required.js +56 -0
- package/dist/lib/validators/strlen.d.ts +4 -0
- package/dist/lib/validators/strlen.js +51 -0
- package/dist/lib/validators/wordCount.d.ts +5 -0
- package/dist/lib/validators/wordCount.js +54 -0
- package/dist/lib/waypoint-url.d.ts +23 -0
- package/dist/lib/waypoint-url.js +52 -0
- package/dist/middleware/body-parser.d.ts +1 -0
- package/dist/middleware/body-parser.js +24 -0
- package/dist/middleware/csrf.d.ts +1 -0
- package/dist/middleware/csrf.js +31 -0
- package/dist/middleware/data.d.ts +5 -0
- package/dist/middleware/data.js +53 -0
- package/dist/middleware/dirname.cjs +1 -0
- package/dist/middleware/dirname.d.cts +2 -0
- package/dist/middleware/gather-fields.d.ts +6 -0
- package/dist/middleware/gather-fields.js +48 -0
- package/dist/middleware/i18n.d.ts +4 -0
- package/dist/middleware/i18n.js +88 -0
- package/dist/middleware/post.d.ts +3 -0
- package/dist/middleware/post.js +57 -0
- package/dist/middleware/pre.d.ts +3 -0
- package/dist/middleware/pre.js +51 -0
- package/dist/middleware/progress-journey.d.ts +6 -0
- package/dist/middleware/progress-journey.js +80 -0
- package/dist/middleware/sanitise-fields.d.ts +5 -0
- package/dist/middleware/sanitise-fields.js +53 -0
- package/dist/middleware/session.d.ts +11 -0
- package/dist/middleware/session.js +121 -0
- package/dist/middleware/skip-waypoint.d.ts +5 -0
- package/dist/middleware/skip-waypoint.js +43 -0
- package/dist/middleware/steer-journey.d.ts +7 -0
- package/dist/middleware/steer-journey.js +62 -0
- package/dist/middleware/validate-fields.d.ts +7 -0
- package/dist/middleware/validate-fields.js +67 -0
- package/dist/mjs/esm-wrapper.js +11 -0
- package/dist/mjs/package.json +3 -0
- package/dist/package.json +3 -0
- package/dist/routes/ancillary.d.ts +11 -0
- package/dist/routes/ancillary.js +27 -0
- package/dist/routes/dirname.cjs +1 -0
- package/dist/routes/dirname.d.cts +2 -0
- package/dist/routes/journey.d.ts +8 -0
- package/dist/routes/journey.js +127 -0
- package/dist/routes/static.d.ts +26 -0
- package/dist/routes/static.js +68 -0
- package/package.json +64 -89
- package/views/casa/components/checkboxes/template.njk +4 -1
- package/views/casa/components/date-input/template.njk +3 -3
- package/views/casa/components/journey-form/README.md +3 -1
- package/views/casa/components/journey-form/template.njk +1 -1
- package/views/casa/components/postal-address-object/template.njk +5 -5
- package/views/casa/components/radios/template.njk +1 -1
- package/views/casa/errors/static.njk +11 -0
- package/views/casa/layouts/journey.njk +26 -9
- package/views/casa/layouts/main.njk +7 -20
- package/views/casa/partials/scripts.njk +8 -3
- package/views/casa/partials/styles.njk +2 -2
- package/casa.js +0 -208
- package/definitions/review-page.js +0 -60
- package/dist/casa/css/casa.css +0 -1
- package/dist/casa/js/casa.js +0 -1
- package/index.d.ts +0 -121
- package/lib/ConfigIngestor.js +0 -588
- package/lib/GatherModifier.js +0 -14
- package/lib/I18n.js +0 -160
- package/lib/JourneyContext.d.ts +0 -97
- package/lib/JourneyContext.js +0 -552
- package/lib/JourneyMap.js +0 -233
- package/lib/JourneyRoad.js +0 -330
- package/lib/Logger.js +0 -59
- package/lib/PageDictionary.d.ts +0 -11
- package/lib/PageDirectory.js +0 -77
- package/lib/Plan.js +0 -423
- package/lib/RoadConverter.js +0 -153
- package/lib/UserJourney.js +0 -8
- package/lib/Util.js +0 -227
- package/lib/Validation.js +0 -20
- package/lib/bootstrap/end-session.js +0 -44
- package/lib/bootstrap/load-definitions.js +0 -64
- package/lib/commonBodyParser.js +0 -15
- package/lib/enums.js +0 -6
- package/lib/gather-modifiers/index.js +0 -7
- package/lib/gather-modifiers/trimPostalAddressObject.js +0 -75
- package/lib/gather-modifiers/trimWhitespace.js +0 -16
- package/lib/utils/createGetRequest.d.ts +0 -5
- package/lib/utils/createGetRequest.js +0 -59
- package/lib/utils/index.js +0 -11
- package/lib/utils/parseRequest.d.ts +0 -5
- package/lib/utils/parseRequest.js +0 -72
- package/lib/utils/sanitise.js +0 -74
- package/lib/utils/validate.js +0 -32
- package/lib/validation/ArrayObjectField.js +0 -49
- package/lib/validation/ObjectField.js +0 -53
- package/lib/validation/SimpleField.d.ts +0 -11
- package/lib/validation/SimpleField.js +0 -46
- package/lib/validation/ValidationError.d.ts +0 -14
- package/lib/validation/ValidationError.js +0 -170
- package/lib/validation/ValidatorFactory.d.ts +0 -32
- package/lib/validation/ValidatorFactory.js +0 -91
- package/lib/validation/index.js +0 -22
- package/lib/validation/processor/flattenErrorArray.js +0 -24
- package/lib/validation/processor/queue.js +0 -214
- package/lib/validation/processor.js +0 -84
- package/lib/validation/rules/README.md +0 -3
- package/lib/validation/rules/ValidationRules.d.ts +0 -22
- package/lib/validation/rules/dateObject.js +0 -156
- package/lib/validation/rules/email.js +0 -44
- package/lib/validation/rules/inArray.js +0 -61
- package/lib/validation/rules/index.js +0 -23
- package/lib/validation/rules/nino.js +0 -48
- package/lib/validation/rules/optional.js +0 -14
- package/lib/validation/rules/postalAddressObject.js +0 -142
- package/lib/validation/rules/regex.js +0 -39
- package/lib/validation/rules/required.js +0 -57
- package/lib/validation/rules/strlen.js +0 -57
- package/lib/validation/rules/wordCount.js +0 -61
- package/lib/view-filters/formatDateObject.js +0 -35
- package/lib/view-filters/includes.js +0 -10
- package/lib/view-filters/index.js +0 -23
- package/lib/view-filters/mergeObjectsDeep.js +0 -21
- package/lib/view-filters/renderAsAttributes.js +0 -33
- package/middleware/errors/404.js +0 -12
- package/middleware/errors/catch-all.js +0 -27
- package/middleware/errors/index.js +0 -9
- package/middleware/headers/config-defaults.js +0 -57
- package/middleware/headers/headers.js +0 -40
- package/middleware/headers/index.js +0 -9
- package/middleware/i18n/i18n.js +0 -56
- package/middleware/i18n/index.js +0 -16
- package/middleware/index.js +0 -55
- package/middleware/mount/index.js +0 -9
- package/middleware/mount/mount.js +0 -10
- package/middleware/nunjucks/environment.js +0 -57
- package/middleware/nunjucks/index.js +0 -8
- package/middleware/page/csrf.js +0 -37
- package/middleware/page/edit-mode.js +0 -52
- package/middleware/page/gather.js +0 -75
- package/middleware/page/index.js +0 -103
- package/middleware/page/journey-continue.js +0 -157
- package/middleware/page/journey-rails.js +0 -102
- package/middleware/page/prepare-request.js +0 -77
- package/middleware/page/render.js +0 -75
- package/middleware/page/skip.js +0 -72
- package/middleware/page/utils.js +0 -206
- package/middleware/page/validate.js +0 -67
- package/middleware/session/expiry.js +0 -95
- package/middleware/session/genid.js +0 -18
- package/middleware/session/index.js +0 -18
- package/middleware/session/init.js +0 -25
- package/middleware/session/seed.js +0 -50
- package/middleware/session/timeout.js +0 -5
- package/middleware/static/asset-versions.js +0 -23
- package/middleware/static/index.js +0 -104
- package/middleware/static/prepare-assets.js +0 -51
- package/middleware/static/serve-assets.js +0 -58
- package/middleware/variables/index.js +0 -12
- package/middleware/variables/variables.js +0 -35
- package/src/browserconfig.xml +0 -5
- package/src/js/casa.js +0 -132
- package/src/scss/_casaElements.scss +0 -11
- package/src/scss/_casaGovukTemplateJinjaPolyfill.scss +0 -39
- package/src/scss/_casaMountUrl.scss +0 -8
- package/src/scss/casa-ie8.scss +0 -3
- package/src/scss/casa.scss +0 -14
- package/test/unit/templates/README.md +0 -5
- package/test/utils/BaseTestWaypoint.js +0 -106
- package/test/utils/concatWaypoints.js +0 -26
- package/test/utils/index.js +0 -6
- package/test/utils/testTraversal.js +0 -90
- package/views/casa/partials/cookie_message.njk +0 -3
- package/views/casa/partials/phase_banner_alpha.njk +0 -8
- package/views/casa/partials/phase_banner_beta.njk +0 -8
- package/views/casa/review/page-block.njk +0 -8
- package/views/casa/review/review.njk +0 -47
package/lib/JourneyMap.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
const JourneyRoad = require('./JourneyRoad.js');
|
|
2
|
-
const Plan = require('./Plan.js');
|
|
3
|
-
const RoadConverter = require('./RoadConverter.js');
|
|
4
|
-
|
|
5
|
-
const ERR_START_UNDEFINED = 'Start of journey has not been defined!';
|
|
6
|
-
const privates = new WeakMap();
|
|
7
|
-
|
|
8
|
-
class JourneyMap {
|
|
9
|
-
/**
|
|
10
|
-
* The `guid` is only required if you are using multiple journeys, as each one
|
|
11
|
-
* must have a unique identifier. This identifier will be used to prefix
|
|
12
|
-
* waypoints in order to help CASA identify which journey the user is
|
|
13
|
-
* requesting. Thefore, if used, then it must be a valid URL slug.
|
|
14
|
-
*
|
|
15
|
-
* @class
|
|
16
|
-
* @param {string} guid An ID that uniquely represents this journey.
|
|
17
|
-
* @throws {TypeError} When guid is invalid
|
|
18
|
-
* @throws {SyntaxError} When guid is misformatted
|
|
19
|
-
*/
|
|
20
|
-
constructor(guid = null) {
|
|
21
|
-
if (guid !== null) {
|
|
22
|
-
if (typeof guid !== 'string') {
|
|
23
|
-
throw new TypeError('guid must be a string');
|
|
24
|
-
} else if (!guid.match(/^[0-9a-z-]+$/)) {
|
|
25
|
-
throw new SyntaxError('guid must contain only 0-9, a-z, -');
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
privates.set(this, {
|
|
30
|
-
guid,
|
|
31
|
-
startRoad: undefined,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Get guid
|
|
37
|
-
*
|
|
38
|
-
* @returns {string} Journey GUID
|
|
39
|
-
*/
|
|
40
|
-
get guid() {
|
|
41
|
-
return privates.get(this).guid;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Define the starting point for this map - the first road that will be
|
|
46
|
-
* traversed.
|
|
47
|
-
*
|
|
48
|
-
* @param {JourneyRoad} road First road on the journey.
|
|
49
|
-
* @returns {ujMap} (chain).
|
|
50
|
-
* @throws {Error} When a non-Road is given as the starting point
|
|
51
|
-
*/
|
|
52
|
-
startAt(road) {
|
|
53
|
-
const priv = privates.get(this);
|
|
54
|
-
if (!(road instanceof JourneyRoad)) {
|
|
55
|
-
throw new Error('Only Roads may be defined as starting points');
|
|
56
|
-
}
|
|
57
|
-
priv.startRoad = road;
|
|
58
|
-
|
|
59
|
-
privates.set(this, priv);
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Return all possible waypoints on this map. This will follow all roads, and
|
|
65
|
-
* all forks to build up an exhaustive list of registered waypoints.
|
|
66
|
-
*
|
|
67
|
-
* The order of the returned array is insignificant. The purpose of this method
|
|
68
|
-
* is to provide a means of determining if a waypoint exists on the map.
|
|
69
|
-
*
|
|
70
|
-
* @returns {Array} List of all waypoints on the map.
|
|
71
|
-
* @throws {Error} When a starting waypoint is undefined.
|
|
72
|
-
*/
|
|
73
|
-
allWaypoints() {
|
|
74
|
-
const priv = privates.get(this);
|
|
75
|
-
|
|
76
|
-
if (typeof priv.startRoad === 'undefined') {
|
|
77
|
-
throw new Error(ERR_START_UNDEFINED);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const waypoints = [];
|
|
81
|
-
|
|
82
|
-
// Used to keep track of which roads have already been followed so we don't
|
|
83
|
-
// end up with recursions when roads loop back on themselves.
|
|
84
|
-
const followedRoads = [];
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Follow a road.
|
|
88
|
-
*
|
|
89
|
-
* @param {JourneyRoad} road Road to follow.
|
|
90
|
-
* @returns {void}
|
|
91
|
-
* @throws {Error} For invalid POI type.
|
|
92
|
-
*/
|
|
93
|
-
function followRoad(road) {
|
|
94
|
-
if (followedRoads.indexOf(road) > -1) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
followedRoads.push(road);
|
|
98
|
-
|
|
99
|
-
const pois = road.getPOIs();
|
|
100
|
-
for (let i = 0, l = pois.length; i < l; i += 1) {
|
|
101
|
-
const poi = pois[i];
|
|
102
|
-
switch (poi.type) {
|
|
103
|
-
case JourneyRoad.POI_WAYPOINT:
|
|
104
|
-
waypoints.push(poi.id);
|
|
105
|
-
break;
|
|
106
|
-
case JourneyRoad.POI_FORK:
|
|
107
|
-
for (let ri = 0, rl = poi.roads.length; ri < rl; ri += 1) {
|
|
108
|
-
followRoad(poi.roads[ri]);
|
|
109
|
-
}
|
|
110
|
-
break;
|
|
111
|
-
case JourneyRoad.POI_MERGE:
|
|
112
|
-
followRoad(poi.road);
|
|
113
|
-
break;
|
|
114
|
-
case JourneyRoad.POI_END:
|
|
115
|
-
break;
|
|
116
|
-
default:
|
|
117
|
-
throw new Error('Invalid POI type');
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
followRoad(priv.startRoad);
|
|
123
|
-
|
|
124
|
-
return waypoints;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Determine if the map contains the specified waypoint at all. This will look
|
|
129
|
-
* at _all_ waypoints in the map.
|
|
130
|
-
*
|
|
131
|
-
* @param {string} waypointId Waypoint ID to find.
|
|
132
|
-
* @returns {boolean} Whether waypoint is present in the map or not.
|
|
133
|
-
*/
|
|
134
|
-
containsWaypoint(waypointId) {
|
|
135
|
-
return this.allWaypoints().indexOf(waypointId) > -1;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Traverse the map, using the provided context to make decisions on
|
|
140
|
-
* visiting/forking/merging along the way.
|
|
141
|
-
*
|
|
142
|
-
* The resulting list of waypoints include those that either a) have related
|
|
143
|
-
* data in context (i.e. Context[waypoint.id] exists and is not empty) and there
|
|
144
|
-
* are no validation errors on that waypoint, or b) exhaust the list of possible
|
|
145
|
-
* waypoints (we reach the end of the journey).
|
|
146
|
-
*
|
|
147
|
-
* The context associated with a waypoint is considered not-empty if it is an
|
|
148
|
-
* object, and it has at least one attribute specified within that object.
|
|
149
|
-
*
|
|
150
|
-
* If the traversed journey loops back on itself at any point, then the
|
|
151
|
-
* traversal will stop at the last good waypoint.
|
|
152
|
-
*
|
|
153
|
-
* Data and validation contexts are provided separately (rather than passing in
|
|
154
|
-
* a JourneyContext instance, for example) so that caller can arbitrarily decide
|
|
155
|
-
* whether or not to include a validation context whilst traversing.
|
|
156
|
-
*
|
|
157
|
-
* @param {object} dataContext Data for each waypoint in the journey.
|
|
158
|
-
* @param {object} validationContext Validation errors for each waypoint in the journey.
|
|
159
|
-
* @returns {Array} List of waypoint IDs that have been traversed (in order).
|
|
160
|
-
* @throws {Error} When start point is undefined.
|
|
161
|
-
*/
|
|
162
|
-
traverse(dataContext = {}, validationContext = {}) {
|
|
163
|
-
const priv = privates.get(this);
|
|
164
|
-
|
|
165
|
-
if (typeof priv.startRoad === 'undefined') {
|
|
166
|
-
throw new Error(ERR_START_UNDEFINED);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let poi = priv.startRoad.getPOIs()[0];
|
|
170
|
-
const waypoints = [];
|
|
171
|
-
|
|
172
|
-
do {
|
|
173
|
-
// Preventative measure against a looping journey
|
|
174
|
-
if (waypoints.indexOf(poi.id) > -1) {
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
if (typeof poi.show !== 'function' || poi.show(dataContext)) {
|
|
178
|
-
waypoints.push(poi.id);
|
|
179
|
-
if (typeof poi.passable !== 'function' || !poi.passable(dataContext, validationContext)) {
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
poi = poi.nextWaypoint(dataContext);
|
|
184
|
-
} while (poi);
|
|
185
|
-
|
|
186
|
-
return waypoints;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Traverse the whole journey, including future waypoints, based on the given
|
|
191
|
-
* data context. This is a useful function to look ahead and see which waypoints
|
|
192
|
-
* will feature in the user's journey given the current context state.
|
|
193
|
-
*
|
|
194
|
-
* Any forking and conditional logic that features in your UserJourney, must be
|
|
195
|
-
* careful to check that data exists prior to testing it, because this method
|
|
196
|
-
* will not necessarily provide the expected data when executing that logic
|
|
197
|
-
* (because it may not have been gathered yet).
|
|
198
|
-
*
|
|
199
|
-
* @param {object} dataContext Data for each waypoint in the journey.
|
|
200
|
-
* @returns {Array} List of waypoint IDs that have been traversed (in order).
|
|
201
|
-
* @throws {Error} When a starting point is undefined
|
|
202
|
-
*/
|
|
203
|
-
traverseAhead(dataContext = {}) {
|
|
204
|
-
const priv = privates.get(this);
|
|
205
|
-
|
|
206
|
-
if (typeof priv.startRoad === 'undefined') {
|
|
207
|
-
throw new Error(ERR_START_UNDEFINED);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
let poi = priv.startRoad.getPOIs()[0];
|
|
211
|
-
const waypoints = [];
|
|
212
|
-
|
|
213
|
-
do {
|
|
214
|
-
// Preventative measure against a looping journey
|
|
215
|
-
if (waypoints.indexOf(poi.id) > -1) {
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
waypoints.push(poi.id);
|
|
219
|
-
poi = poi.nextWaypoint(dataContext);
|
|
220
|
-
} while (poi);
|
|
221
|
-
|
|
222
|
-
return waypoints;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
convertToPlan() {
|
|
226
|
-
const plan = new Plan();
|
|
227
|
-
const { startRoad } = privates.get(this);
|
|
228
|
-
plan.addOrigin('main', startRoad.getPOIs()[0].id);
|
|
229
|
-
return new RoadConverter(plan, startRoad).convert().plan;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
module.exports = JourneyMap;
|
package/lib/JourneyRoad.js
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
const privates = new WeakMap();
|
|
2
|
-
|
|
3
|
-
/* --------------------------------------------------------------------- Road */
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Road.
|
|
7
|
-
*/
|
|
8
|
-
class JourneyRoad {
|
|
9
|
-
/**
|
|
10
|
-
* JourneyRoad.
|
|
11
|
-
*
|
|
12
|
-
* @class
|
|
13
|
-
*/
|
|
14
|
-
constructor() {
|
|
15
|
-
// "Points of Interest" along our journey.
|
|
16
|
-
// All points of interest will have a `nextWaypoint()` method that attempts
|
|
17
|
-
// to determine the next waypoint in the journey after each POI.
|
|
18
|
-
privates.set(this, {
|
|
19
|
-
pois: [],
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** ..
|
|
24
|
-
* Add a new waypoint(s) to the journey. A waypoint is simply a string (or a
|
|
25
|
-
* function - see below) that uniquely identifies a stopping point on the
|
|
26
|
-
* journey. Typically this will be the URL slug of a single page.
|
|
27
|
-
*
|
|
28
|
-
* You can also use a function to describe a specific waypoint, in which case
|
|
29
|
-
* the function will be executed (at runtime) to determine if the waypoint
|
|
30
|
-
* should be included or not (based on a given data context). In this case, pass
|
|
31
|
-
* the waypoint ID and function as an array:
|
|
32
|
-
* AddWaypoints([
|
|
33
|
-
* 'normal-waypoint',
|
|
34
|
-
* ['conditional-waypoint', (context) => {...return bool...}]
|
|
35
|
-
* ]);
|
|
36
|
-
*
|
|
37
|
-
* You can also define waypoints as objects, which supports additional
|
|
38
|
-
* functionality. E.g.
|
|
39
|
-
* AddWaypoints([
|
|
40
|
-
* 'normal-waypoint',
|
|
41
|
-
* {
|
|
42
|
-
* id: 'conditional-waypoint',
|
|
43
|
-
* is_present: (context) => {...return bool...},
|
|
44
|
-
* is_passable: (dataContext, validationContext) => {...return bool...},
|
|
45
|
-
* }
|
|
46
|
-
* ]);
|
|
47
|
-
*
|
|
48
|
-
* The `is_passable` function here determines if the waypoint should be
|
|
49
|
-
* considered complete. By default this checks for a) the presence of data
|
|
50
|
-
* held against that waypoint, and b) an absence of validation errors
|
|
51
|
-
* associated with the waypoint.
|
|
52
|
-
*
|
|
53
|
-
* @param {Array | string} points Add these waypoint(s) in the order defined.
|
|
54
|
-
* @returns {JourneyRoad} (chain).
|
|
55
|
-
* @throws {Error} When waypoint ordering is invalid
|
|
56
|
-
* @throws {TypeError} When any waypoint definitions are invalid
|
|
57
|
-
*/
|
|
58
|
-
addWaypoints(points) {
|
|
59
|
-
const priv = privates.get(this);
|
|
60
|
-
|
|
61
|
-
// Waypoints can only be added after other waypoints; never after forks or
|
|
62
|
-
// merges
|
|
63
|
-
if (
|
|
64
|
-
priv.pois.length
|
|
65
|
-
&& priv.pois[priv.pois.length - 1].type !== JourneyRoad.POI_WAYPOINT
|
|
66
|
-
) {
|
|
67
|
-
throw new Error('Waypoints can only follow other waypoints.');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Convert to array
|
|
71
|
-
const waypoints = Array.isArray(points) ? points : [points];
|
|
72
|
-
|
|
73
|
-
// Validate each waypoint
|
|
74
|
-
// If an Array, it must be [<String>, <Function>]
|
|
75
|
-
// If an Object it must contain at least an `id` attribute
|
|
76
|
-
waypoints.forEach((w) => {
|
|
77
|
-
if (Array.isArray(w)) {
|
|
78
|
-
if (w.length !== 2) {
|
|
79
|
-
throw new SyntaxError('Array waypoints must contain 2 elements');
|
|
80
|
-
} else if (typeof w[0] !== 'string') {
|
|
81
|
-
throw new TypeError('The first element in an Array waypoint must be a string');
|
|
82
|
-
} else if (typeof w[1] !== 'function') {
|
|
83
|
-
throw new TypeError('The second element in an Array waypoint must be a function');
|
|
84
|
-
}
|
|
85
|
-
} else if (Object.prototype.toString.call(w) === '[object Object]') {
|
|
86
|
-
if (!Object.prototype.hasOwnProperty.call(w, 'id')) {
|
|
87
|
-
throw new SyntaxError('Object waypoints must contain an id element');
|
|
88
|
-
} else if (typeof w.id !== 'string') {
|
|
89
|
-
throw new TypeError('Object waypoint id must be a string');
|
|
90
|
-
}
|
|
91
|
-
if (Object.prototype.hasOwnProperty.call(w, 'is_present') && typeof w.is_present !== 'function') {
|
|
92
|
-
throw new TypeError('Object waypoint is_present condition must be a function');
|
|
93
|
-
}
|
|
94
|
-
if (Object.prototype.hasOwnProperty.call(w, 'is_passable') && typeof w.is_passable !== 'function') {
|
|
95
|
-
throw new TypeError('Object waypoint is_passable condition must be a function');
|
|
96
|
-
}
|
|
97
|
-
} else if (typeof w !== 'string') {
|
|
98
|
-
throw new TypeError('Waypoint must be a string, object or array');
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* This is the condition that will be executed, by default, to test whether
|
|
104
|
-
* a waypoint is "passable" during traversal calls. It must be bind-able as
|
|
105
|
-
* we attach the waypoint ID as `this.id`.
|
|
106
|
-
* This can be overriden per-waypoint by passing in a custom `is_passable`
|
|
107
|
-
* function.
|
|
108
|
-
*
|
|
109
|
-
* @param {object} dc Data context.
|
|
110
|
-
* @param {object} vc Validation context.
|
|
111
|
-
* @returns {bool} True if the waypoint is passable.
|
|
112
|
-
*/
|
|
113
|
-
function defaultPassableCondition(dc, vc) {
|
|
114
|
-
return (dc
|
|
115
|
-
&& Object.prototype.hasOwnProperty.call(dc, this.id)
|
|
116
|
-
&& typeof dc[this.id] === 'object'
|
|
117
|
-
&& Object.keys(dc[this.id]).length !== 0
|
|
118
|
-
&& (
|
|
119
|
-
!Object.prototype.hasOwnProperty.call(vc, this.id)
|
|
120
|
-
|| Object.keys(vc[this.id]).length === 0
|
|
121
|
-
)
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Store all waypoints
|
|
126
|
-
for (let index = 0, l = waypoints.length; index < l; index += 1) {
|
|
127
|
-
let waypointId;
|
|
128
|
-
let waypointShowConditional;
|
|
129
|
-
let waypointPassableConditional;
|
|
130
|
-
|
|
131
|
-
if (Array.isArray(waypoints[index])) {
|
|
132
|
-
waypointId = String(waypoints[index][0]);
|
|
133
|
-
/* eslint-disable-next-line prefer-destructuring */
|
|
134
|
-
waypointShowConditional = waypoints[index][1];
|
|
135
|
-
waypointPassableConditional = defaultPassableCondition.bind({ id: waypointId });
|
|
136
|
-
} else if (Object.prototype.toString.call(waypoints[index]) === '[object Object]') {
|
|
137
|
-
waypointId = String(waypoints[index].id);
|
|
138
|
-
waypointShowConditional = waypoints[index].is_present || (() => (true));
|
|
139
|
-
waypointPassableConditional = waypoints[index].is_passable
|
|
140
|
-
|| defaultPassableCondition.bind({ id: waypointId });
|
|
141
|
-
} else {
|
|
142
|
-
waypointId = waypoints[index];
|
|
143
|
-
waypointShowConditional = () => (true);
|
|
144
|
-
waypointPassableConditional = defaultPassableCondition.bind({ id: waypointId });
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
priv.pois.push({
|
|
148
|
-
id: waypointId,
|
|
149
|
-
type: JourneyRoad.POI_WAYPOINT,
|
|
150
|
-
show: waypointShowConditional,
|
|
151
|
-
passable: waypointPassableConditional,
|
|
152
|
-
nextWaypoint: (context) => {
|
|
153
|
-
const nextPOI = this.getPOIs()[index + 1];
|
|
154
|
-
if (
|
|
155
|
-
typeof nextPOI === 'undefined'
|
|
156
|
-
|| nextPOI === null
|
|
157
|
-
|| nextPOI.type === JourneyRoad.POI_END
|
|
158
|
-
) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
// Handle potential exceptions in the userland `show()` function
|
|
162
|
-
try {
|
|
163
|
-
if (
|
|
164
|
-
nextPOI.type === JourneyRoad.POI_WAYPOINT
|
|
165
|
-
&& nextPOI.show(context)
|
|
166
|
-
) {
|
|
167
|
-
return nextPOI;
|
|
168
|
-
}
|
|
169
|
-
return nextPOI.nextWaypoint(context);
|
|
170
|
-
} catch (ex) {
|
|
171
|
-
return JourneyRoad.WAYPOINT_FAULT_OBJ;
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Chain
|
|
178
|
-
privates.set(this, priv);
|
|
179
|
-
return this;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Add a fork in the road. The `test()` function is executed to determine which
|
|
184
|
-
* of the specified `roads` should be taken, given some context about the user's
|
|
185
|
-
* journey.
|
|
186
|
-
*
|
|
187
|
-
* Function interface for `test()`:
|
|
188
|
-
* function (roads, context) {
|
|
189
|
-
* ... return one of the roads based on context ...
|
|
190
|
-
* }
|
|
191
|
-
*
|
|
192
|
-
* @param {Array} roads Array of road choices (order is important)
|
|
193
|
-
* @param {Function} test Function used to determine which of the roads to take
|
|
194
|
-
* @returns {JourneyRoad} (chain)
|
|
195
|
-
* @throws {Error} When a fork is created prematurely
|
|
196
|
-
*/
|
|
197
|
-
fork(roads, test) {
|
|
198
|
-
const priv = privates.get(this);
|
|
199
|
-
|
|
200
|
-
// A fork can only follow a waypoint on the journey
|
|
201
|
-
if (
|
|
202
|
-
priv.pois.length
|
|
203
|
-
&& priv.pois[priv.pois.length - 1].type !== JourneyRoad.POI_WAYPOINT
|
|
204
|
-
) {
|
|
205
|
-
throw new Error('Forks can only follow waypoints.');
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Store fork
|
|
209
|
-
priv.pois.push({
|
|
210
|
-
type: JourneyRoad.POI_FORK,
|
|
211
|
-
test,
|
|
212
|
-
roads,
|
|
213
|
-
nextWaypoint: (context) => {
|
|
214
|
-
// Fork logic functions are from userland so we need to handle
|
|
215
|
-
// exceptions cleanly in case they are not handled correctly within
|
|
216
|
-
// those functions. In such scenarios, a `journey-fault` waypoint is
|
|
217
|
-
// returned, after which no other waypoints can be accessed.
|
|
218
|
-
// This will fall through to a 404 response, but the application should
|
|
219
|
-
// add an Express route to handle this more specifically.
|
|
220
|
-
try {
|
|
221
|
-
const road = test.call(this, roads, context);
|
|
222
|
-
const pois = road ? road.getPOIs() : [];
|
|
223
|
-
if (pois.length && typeof pois[0].show === 'function') {
|
|
224
|
-
return pois[0].show(context) ? pois[0] : pois[0].nextWaypoint(context);
|
|
225
|
-
}
|
|
226
|
-
return null;
|
|
227
|
-
} catch (ex) {
|
|
228
|
-
return JourneyRoad.WAYPOINT_FAULT_OBJ;
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Chain
|
|
234
|
-
privates.set(this, priv);
|
|
235
|
-
return this;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Merge this road into another road.
|
|
240
|
-
*
|
|
241
|
-
* @param {JourneyRoad} road Road into which this one will merge.
|
|
242
|
-
* @returns {JourneyRoad} (chain).
|
|
243
|
-
* @throws {Error} When merge is create prematurely.
|
|
244
|
-
*/
|
|
245
|
-
mergeWith(road) {
|
|
246
|
-
const priv = privates.get(this);
|
|
247
|
-
|
|
248
|
-
// A merge can only follow a waypoint on the journey
|
|
249
|
-
if (
|
|
250
|
-
priv.pois.length
|
|
251
|
-
&& priv.pois[priv.pois.length - 1].type !== JourneyRoad.POI_WAYPOINT
|
|
252
|
-
) {
|
|
253
|
-
throw new Error('Merges can only follow waypoints.');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Store merge
|
|
257
|
-
priv.pois.push({
|
|
258
|
-
type: JourneyRoad.POI_MERGE,
|
|
259
|
-
road,
|
|
260
|
-
nextWaypoint: (context) => {
|
|
261
|
-
// Handle potential exceptions in userland `show()` function.
|
|
262
|
-
try {
|
|
263
|
-
const pois = road.getPOIs();
|
|
264
|
-
if (pois.length && typeof pois[0].show === 'function') {
|
|
265
|
-
return pois[0].show(context) ? pois[0] : pois[0].nextWaypoint(context);
|
|
266
|
-
}
|
|
267
|
-
return null;
|
|
268
|
-
} catch (ex) {
|
|
269
|
-
return JourneyRoad.WAYPOINT_FAULT_OBJ;
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// Chain
|
|
275
|
-
privates.set(this, priv);
|
|
276
|
-
return this;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Road ends here.
|
|
281
|
-
*
|
|
282
|
-
* @returns {JourneyRoad} (chain).
|
|
283
|
-
* @throws {Error} When the road ends prematurely.
|
|
284
|
-
*/
|
|
285
|
-
end() {
|
|
286
|
-
const priv = privates.get(this);
|
|
287
|
-
|
|
288
|
-
// A merge can only follow a waypoint on the journey
|
|
289
|
-
if (
|
|
290
|
-
priv.pois.length
|
|
291
|
-
&& priv.pois[priv.pois.length - 1].type !== JourneyRoad.POI_WAYPOINT
|
|
292
|
-
) {
|
|
293
|
-
throw new Error('Roads can only finish after a waypoint.');
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Store merge
|
|
297
|
-
priv.pois.push({
|
|
298
|
-
id: '__END__',
|
|
299
|
-
type: JourneyRoad.POI_END,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
// Chain
|
|
303
|
-
privates.set(this, priv);
|
|
304
|
-
return this;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Return a copy of all POIs along this road.
|
|
309
|
-
*
|
|
310
|
-
* @returns {Array} POI objects.
|
|
311
|
-
*/
|
|
312
|
-
getPOIs() {
|
|
313
|
-
const priv = privates.get(this);
|
|
314
|
-
return Array.prototype.slice.call(priv.pois);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
JourneyRoad.POI_WAYPOINT = 'waypoint';
|
|
319
|
-
JourneyRoad.POI_FORK = 'fork';
|
|
320
|
-
JourneyRoad.POI_MERGE = 'merge';
|
|
321
|
-
JourneyRoad.POI_END = 'end';
|
|
322
|
-
|
|
323
|
-
JourneyRoad.WAYPOINT_FAULT_ID = 'journey-fault';
|
|
324
|
-
JourneyRoad.WAYPOINT_FAULT_OBJ = {
|
|
325
|
-
id: JourneyRoad.WAYPOINT_FAULT_ID,
|
|
326
|
-
type: JourneyRoad.POI_WAYPOINT,
|
|
327
|
-
nextWaypoint: () => (null),
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
module.exports = JourneyRoad;
|
package/lib/Logger.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CASA logging wrapper. Provide a series of convenient logging functions, ready
|
|
3
|
-
* pre-fixed with the CASA namespace.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
global.GOVUK_CASA_DEBUG_NS = 'casa';
|
|
7
|
-
|
|
8
|
-
const colors = require('colors/safe');
|
|
9
|
-
const ndebug = require('debug');
|
|
10
|
-
|
|
11
|
-
module.exports = function Logger(suffix) {
|
|
12
|
-
const ns = GOVUK_CASA_DEBUG_NS + (suffix ? `:${suffix}` : '');
|
|
13
|
-
|
|
14
|
-
let sessionId = '';
|
|
15
|
-
|
|
16
|
-
const error = ndebug(`${ns}:error`);
|
|
17
|
-
const fatal = ndebug(`${ns}:fatal`);
|
|
18
|
-
|
|
19
|
-
const info = ndebug(`${ns}:info`);
|
|
20
|
-
const warn = ndebug(`${ns}:warn`);
|
|
21
|
-
const debug = ndebug(`${ns}:debug`);
|
|
22
|
-
const trace = ndebug(`${ns}:trace`);
|
|
23
|
-
info.log = console.info.bind(console); /* eslint-disable-line no-console */
|
|
24
|
-
warn.log = console.warn.bind(console); /* eslint-disable-line no-console */
|
|
25
|
-
debug.log = console.log.bind(console); /* eslint-disable-line no-console */
|
|
26
|
-
trace.log = console.log.bind(console); /* eslint-disable-line no-console */
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Set the session ID for all messages in this debugger.
|
|
30
|
-
*
|
|
31
|
-
* @param {string} sid Session ID].
|
|
32
|
-
* @returns {void}
|
|
33
|
-
*/
|
|
34
|
-
function setSessionId(sid) {
|
|
35
|
-
sessionId = sid;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Wrapper for appending the session ID to all messages.
|
|
40
|
-
*
|
|
41
|
-
* @param {...string} args Message(s).
|
|
42
|
-
* @returns {void}
|
|
43
|
-
*/
|
|
44
|
-
function writer(...args) {
|
|
45
|
-
const logArgs = args;
|
|
46
|
-
logArgs[0] += sessionId ? colors.blue(` [session: ${sessionId}]`) : '';
|
|
47
|
-
this(...logArgs);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
trace: writer.bind(trace),
|
|
52
|
-
info: writer.bind(info),
|
|
53
|
-
debug: writer.bind(debug),
|
|
54
|
-
warn: writer.bind(warn),
|
|
55
|
-
error: writer.bind(error),
|
|
56
|
-
fatal: writer.bind(fatal),
|
|
57
|
-
setSessionId,
|
|
58
|
-
};
|
|
59
|
-
};
|
package/lib/PageDictionary.d.ts
DELETED
package/lib/PageDirectory.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple wrapper around all the page definitions.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const privates = new WeakMap();
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* PageDirectory class.
|
|
9
|
-
*/
|
|
10
|
-
class PageDirectory {
|
|
11
|
-
/**
|
|
12
|
-
* Constructor
|
|
13
|
-
*
|
|
14
|
-
* @param {object} pages Page meta data object (indexed by the page id)
|
|
15
|
-
* @throws {Error} If page id is invalid url component, or meta not an object
|
|
16
|
-
*/
|
|
17
|
-
constructor(pages = {}) {
|
|
18
|
-
// Set `id` property for each page so we don't need to keep a separate list
|
|
19
|
-
// of object keys
|
|
20
|
-
const seededPages = Object.create(null);
|
|
21
|
-
Object.keys(pages).forEach((pid) => {
|
|
22
|
-
seededPages[pid] = Object.assign(pages[pid], {
|
|
23
|
-
id: pid,
|
|
24
|
-
});
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
privates.set(this, {
|
|
28
|
-
pages: seededPages,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Validate:
|
|
32
|
-
// - Check if page IDs are appropriate for use as part of URLs
|
|
33
|
-
// - Check that required attributes are present
|
|
34
|
-
Object.keys(pages).forEach((pid) => {
|
|
35
|
-
if (!pid.match(/^[0-9a-z-/]+$/)) {
|
|
36
|
-
throw new Error(`Page ID '${pid}' must contain only 0-9, a-z, -, /`);
|
|
37
|
-
} else if (typeof pages[pid] !== 'object') {
|
|
38
|
-
throw new Error('Page metadata must be an object');
|
|
39
|
-
} else if (typeof pages[pid].view === 'undefined') {
|
|
40
|
-
throw new Error(`Page metadata view is missing for '${pid}'`);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Get all page IDs in the directory.
|
|
47
|
-
*
|
|
48
|
-
* @returns {Array} Page IDs.
|
|
49
|
-
*/
|
|
50
|
-
getAllPageIds() {
|
|
51
|
-
const priv = privates.get(this);
|
|
52
|
-
return Object.keys(priv.pages);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get page metadata for specific page
|
|
57
|
-
*
|
|
58
|
-
* @param {string} pageId Page ID
|
|
59
|
-
* @returns {object} Page metadata
|
|
60
|
-
*/
|
|
61
|
-
getPageMeta(pageId) {
|
|
62
|
-
const priv = privates.get(this);
|
|
63
|
-
return priv.pages[pageId];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Get all pages.
|
|
68
|
-
*
|
|
69
|
-
* @returns {object} All pages indexed by waypoint ID.
|
|
70
|
-
*/
|
|
71
|
-
getPages() {
|
|
72
|
-
const priv = privates.get(this);
|
|
73
|
-
return priv.pages;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
module.exports = PageDirectory;
|