hof 22.8.4-unhandled-error-fix-beta.1 → 22.9.0-beta
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 +16 -0
- package/README.md +30 -0
- package/config/hof-defaults.js +6 -1
- package/frontend/template-partials/views/layout.html +2 -8
- package/frontend/themes/gov-uk/styles/_cookie-banner.scss +0 -3
- package/hof-22.9.0.tgz +0 -0
- package/lib/settings.js +1 -0
- package/model/index.js +1 -1
- package/package/.eslintignore +1 -0
- package/package/CHANGELOG.md +232 -0
- package/package/LICENSE +21 -0
- package/package/README.md +1887 -0
- package/package/bin/hof-build +10 -0
- package/package/bin/hof-transpiler +12 -0
- package/package/build/helpers/importer.js +29 -0
- package/package/build/helpers/local.js +35 -0
- package/package/build/helpers/resolver/import.js +32 -0
- package/package/build/helpers/resolver/nearest-package-root.js +33 -0
- package/package/build/helpers/resolver/package.js +29 -0
- package/package/build/helpers/resolver.js +16 -0
- package/package/build/index.js +49 -0
- package/package/build/lib/env.js +36 -0
- package/package/build/lib/mkdir.js +9 -0
- package/package/build/lib/run.js +17 -0
- package/package/build/lib/spawn.js +18 -0
- package/package/build/tasks/browserify/compress.js +15 -0
- package/package/build/tasks/browserify/index.js +48 -0
- package/package/build/tasks/build/index.js +6 -0
- package/package/build/tasks/images/index.js +27 -0
- package/package/build/tasks/index.js +8 -0
- package/package/build/tasks/sass/index.js +67 -0
- package/package/build/tasks/translate/index.js +20 -0
- package/package/build/tasks/watch/index.js +161 -0
- package/package/components/address-lookup/default-model.js +76 -0
- package/package/components/address-lookup/defaults.js +25 -0
- package/package/components/address-lookup/index.js +251 -0
- package/package/components/address-lookup/templates/address-lookup.html +14 -0
- package/package/components/address-lookup/templates/address.html +22 -0
- package/package/components/address-lookup/templates/postcode.html +9 -0
- package/package/components/clear-session/Readme.md +46 -0
- package/package/components/clear-session/index.js +26 -0
- package/package/components/combine-and-loop-fields/Readme.md +42 -0
- package/package/components/combine-and-loop-fields/index.js +156 -0
- package/package/components/date/fields.js +16 -0
- package/package/components/date/index.js +172 -0
- package/package/components/date/templates/date.html +20 -0
- package/package/components/emailer/assets/images/govuk_logotype_email.png +0 -0
- package/package/components/emailer/assets/images/ho_crest_27px.png +0 -0
- package/package/components/emailer/assets/images/spacer.gif +0 -0
- package/package/components/emailer/email-service.js +51 -0
- package/package/components/emailer/emailer.js +53 -0
- package/package/components/emailer/index.js +74 -0
- package/package/components/emailer/transports/debug.js +74 -0
- package/package/components/emailer/transports/index.js +8 -0
- package/package/components/emailer/transports/ses.js +36 -0
- package/package/components/emailer/transports/smtp.js +26 -0
- package/package/components/emailer/transports/stub.js +5 -0
- package/package/components/emailer/views/layout.html +63 -0
- package/package/components/homeoffice-countries/index.js +22 -0
- package/package/components/index.js +13 -0
- package/package/components/notify/index.js +62 -0
- package/package/components/notify/notify.js +51 -0
- package/package/components/session-timeout-warning/index.js +67 -0
- package/package/components/summary/index.js +237 -0
- package/package/config/builder-defaults.js +45 -0
- package/package/config/component-defaults.js +13 -0
- package/package/config/hof-defaults.js +65 -0
- package/package/config/rate-limits.js +20 -0
- package/package/config/sanitisation-rules.js +32 -0
- package/package/controller/base-controller.js +296 -0
- package/package/controller/behaviour-hooks.js +51 -0
- package/package/controller/behaviour-session.js +64 -0
- package/package/controller/controller.js +258 -0
- package/package/controller/deprecate-error.js +10 -0
- package/package/controller/formatting/formatters.js +70 -0
- package/package/controller/formatting/index.js +32 -0
- package/package/controller/index.js +17 -0
- package/package/controller/validation/email.js +30 -0
- package/package/controller/validation/index.js +101 -0
- package/package/controller/validation/validators.js +181 -0
- package/package/controller/validation-error.js +14 -0
- package/package/frontend/govuk-template/build/config.js +24 -0
- package/package/frontend/govuk-template/build/govuk_template.html +102 -0
- package/package/frontend/govuk-template/build/index.js +23 -0
- package/package/frontend/govuk-template/govuk_template_generated.html +102 -0
- package/package/frontend/govuk-template/index.js +29 -0
- package/package/frontend/index.js +9 -0
- package/package/frontend/template-mixins/mixins/helpers.js +103 -0
- package/package/frontend/template-mixins/mixins/index.js +37 -0
- package/package/frontend/template-mixins/mixins/render.js +12 -0
- package/package/frontend/template-mixins/mixins/template-mixins.js +520 -0
- package/package/frontend/template-mixins/partials/forms/checkbox-group.html +47 -0
- package/package/frontend/template-mixins/partials/forms/checkbox.html +16 -0
- package/package/frontend/template-mixins/partials/forms/input-submit.html +1 -0
- package/package/frontend/template-mixins/partials/forms/input-text-date.html +37 -0
- package/package/frontend/template-mixins/partials/forms/input-text-group.html +45 -0
- package/package/frontend/template-mixins/partials/forms/option-group.html +43 -0
- package/package/frontend/template-mixins/partials/forms/select.html +17 -0
- package/package/frontend/template-mixins/partials/forms/textarea-group.html +37 -0
- package/package/frontend/template-mixins/partials/mixins/panel.html +4 -0
- package/package/frontend/template-partials/index.js +9 -0
- package/package/frontend/template-partials/translations/index.js +26 -0
- package/package/frontend/template-partials/translations/src/cy/base.json +4 -0
- package/package/frontend/template-partials/translations/src/cy/buttons.json +6 -0
- package/package/frontend/template-partials/translations/src/cy/cookies.json +104 -0
- package/package/frontend/template-partials/translations/src/cy/errorlist.json +6 -0
- package/package/frontend/template-partials/translations/src/cy/errors.json +18 -0
- package/package/frontend/template-partials/translations/src/cy/terms.json +28 -0
- package/package/frontend/template-partials/translations/src/en/accessibility.json +43 -0
- package/package/frontend/template-partials/translations/src/en/base.json +5 -0
- package/package/frontend/template-partials/translations/src/en/buttons.json +10 -0
- package/package/frontend/template-partials/translations/src/en/cookies.json +116 -0
- package/package/frontend/template-partials/translations/src/en/errorlist.json +7 -0
- package/package/frontend/template-partials/translations/src/en/errors.json +35 -0
- package/package/frontend/template-partials/translations/src/en/exit.json +5 -0
- package/package/frontend/template-partials/translations/src/en/fields.json +5 -0
- package/package/frontend/template-partials/translations/src/en/journey.json +6 -0
- package/package/frontend/template-partials/translations/src/en/save-and-exit.json +4 -0
- package/package/frontend/template-partials/translations/src/en/terms.json +28 -0
- package/package/frontend/template-partials/views/404.html +9 -0
- package/package/frontend/template-partials/views/accessibility.html +55 -0
- package/package/frontend/template-partials/views/confirm.html +8 -0
- package/package/frontend/template-partials/views/confirmation.html +19 -0
- package/package/frontend/template-partials/views/content/en/what-happens-next.md +0 -0
- package/package/frontend/template-partials/views/cookie-error.html +1 -0
- package/package/frontend/template-partials/views/cookies.html +84 -0
- package/package/frontend/template-partials/views/email/data-row.html +4 -0
- package/package/frontend/template-partials/views/email/formatted.html +12 -0
- package/package/frontend/template-partials/views/email/layout.html +63 -0
- package/package/frontend/template-partials/views/email/raw.html +11 -0
- package/package/frontend/template-partials/views/email/section-row.html +3 -0
- package/package/frontend/template-partials/views/error.html +20 -0
- package/package/frontend/template-partials/views/exit.html +9 -0
- package/package/frontend/template-partials/views/feedback-submitted.html +11 -0
- package/package/frontend/template-partials/views/layout.html +55 -0
- package/package/frontend/template-partials/views/partials/analytics-table.html +25 -0
- package/package/frontend/template-partials/views/partials/back.html +5 -0
- package/package/frontend/template-partials/views/partials/bullet-list.html +7 -0
- package/package/frontend/template-partials/views/partials/confirmation-alert.html +6 -0
- package/package/frontend/template-partials/views/partials/continue.html +5 -0
- package/package/frontend/template-partials/views/partials/cookie-banner.html +29 -0
- package/package/frontend/template-partials/views/partials/cookie-notification.html +4 -0
- package/package/frontend/template-partials/views/partials/cookie-settings-button.html +1 -0
- package/package/frontend/template-partials/views/partials/cookie-settings-radio.html +8 -0
- package/package/frontend/template-partials/views/partials/details-summary.html +8 -0
- package/package/frontend/template-partials/views/partials/external-link.html +1 -0
- package/package/frontend/template-partials/views/partials/form.html +10 -0
- package/package/frontend/template-partials/views/partials/gatag.html +60 -0
- package/package/frontend/template-partials/views/partials/head.html +31 -0
- package/package/frontend/template-partials/views/partials/heading.html +11 -0
- package/package/frontend/template-partials/views/partials/items-table.html +32 -0
- package/package/frontend/template-partials/views/partials/maincontent-left.html +10 -0
- package/package/frontend/template-partials/views/partials/navigation.html +8 -0
- package/package/frontend/template-partials/views/partials/page.html +23 -0
- package/package/frontend/template-partials/views/partials/panel-indent.html +3 -0
- package/package/frontend/template-partials/views/partials/session-cookies-table.html +28 -0
- package/package/frontend/template-partials/views/partials/session-timeout-warning.html +38 -0
- package/package/frontend/template-partials/views/partials/summary-table-row.html +14 -0
- package/package/frontend/template-partials/views/partials/summary-table.html +8 -0
- package/package/frontend/template-partials/views/partials/table.html +18 -0
- package/package/frontend/template-partials/views/partials/validation-list.html +3 -0
- package/package/frontend/template-partials/views/partials/validation-summary.html +25 -0
- package/package/frontend/template-partials/views/partials/warn.html +7 -0
- package/package/frontend/template-partials/views/rate-limit-error.html +10 -0
- package/package/frontend/template-partials/views/save-and-exit.html +17 -0
- package/package/frontend/template-partials/views/service-unavailable.html +13 -0
- package/package/frontend/template-partials/views/session-timeout.html +7 -0
- package/package/frontend/template-partials/views/step.html +14 -0
- package/package/frontend/template-partials/views/terms.html +26 -0
- package/package/frontend/themes/gov-uk/client-js/cookieSettings.js +145 -0
- package/package/frontend/themes/gov-uk/client-js/govuk-cookies.js +121 -0
- package/package/frontend/themes/gov-uk/client-js/index.js +27 -0
- package/package/frontend/themes/gov-uk/client-js/session-timeout-dialog.js +348 -0
- package/package/frontend/themes/gov-uk/client-js/skip-to-main.js +19 -0
- package/package/frontend/themes/gov-uk/index.js +9 -0
- package/package/frontend/themes/gov-uk/styles/_base.scss +17 -0
- package/package/frontend/themes/gov-uk/styles/_check_your_answers.scss +155 -0
- package/package/frontend/themes/gov-uk/styles/_cookie-banner.scss +111 -0
- package/package/frontend/themes/gov-uk/styles/_cookie-settings.scss +33 -0
- package/package/frontend/themes/gov-uk/styles/_govuk_frontend_toolkit.scss +23 -0
- package/package/frontend/themes/gov-uk/styles/_helpers.scss +5 -0
- package/package/frontend/themes/gov-uk/styles/_layout.scss +125 -0
- package/package/frontend/themes/gov-uk/styles/_panel-indent.scss +27 -0
- package/package/frontend/themes/gov-uk/styles/_pdf.scss +42 -0
- package/package/frontend/themes/gov-uk/styles/_session-timeout-dialog.scss +121 -0
- package/package/frontend/themes/gov-uk/styles/_typography.scss +27 -0
- package/package/frontend/themes/gov-uk/styles/_variables.scss +11 -0
- package/package/frontend/themes/gov-uk/styles/govuk.scss +43 -0
- package/package/frontend/themes/gov-uk/styles/mixins.scss +16 -0
- package/package/frontend/themes/gov-uk/styles/modules/_alerts.scss +73 -0
- package/package/frontend/themes/gov-uk/styles/modules/_buttons.scss +5 -0
- package/package/frontend/themes/gov-uk/styles/modules/_character-count.scss +8 -0
- package/package/frontend/themes/gov-uk/styles/modules/_confirm-page.scss +20 -0
- package/package/frontend/themes/gov-uk/styles/modules/_lists.scss +5 -0
- package/package/frontend/themes/gov-uk/styles/modules/_progressive-reveal.scss +17 -0
- package/package/frontend/themes/gov-uk/styles/modules/_validation.scss +51 -0
- package/package/frontend/themes/index.js +5 -0
- package/package/frontend/toolkit/assets/images/passports/new-window-link-blue.png +0 -0
- package/package/frontend/toolkit/assets/images/passports/new-window-link.png +0 -0
- package/package/frontend/toolkit/assets/images/spinner.gif +0 -0
- package/package/frontend/toolkit/assets/javascript/character-count.js +99 -0
- package/package/frontend/toolkit/assets/javascript/form-focus.js +101 -0
- package/package/frontend/toolkit/assets/javascript/helpers.js +177 -0
- package/package/frontend/toolkit/assets/javascript/progressive-reveal.js +72 -0
- package/package/frontend/toolkit/assets/javascript/validation.js +71 -0
- package/package/frontend/toolkit/assets/javascript/vendor/details.polyfill.js +189 -0
- package/package/frontend/toolkit/assets/javascript/vendor/indexof.polyfill.js +39 -0
- package/package/frontend/toolkit/assets/javascript/vendor/safari-cachebuster.js +6 -0
- package/package/frontend/toolkit/assets/stylesheets/_base.scss +17 -0
- package/package/frontend/toolkit/assets/stylesheets/_helpers.scss +5 -0
- package/package/frontend/toolkit/assets/stylesheets/_layout.scss +118 -0
- package/package/frontend/toolkit/assets/stylesheets/_typography.scss +27 -0
- package/package/frontend/toolkit/assets/stylesheets/_variables.scss +11 -0
- package/package/frontend/toolkit/assets/stylesheets/app.scss +30 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_buttons.scss +47 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_details.scss +38 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_elements-typography.scss +175 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_forms.scss +167 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_helpers.scss +39 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_layout.scss +67 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_lists.scss +40 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_panels.scss +29 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_reset.scss +33 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_tables.scss +33 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-block-labels.scss +63 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-date.scss +39 -0
- package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-validation.scss +63 -0
- package/package/frontend/toolkit/assets/stylesheets/mixins.scss +16 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_alerts.scss +73 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_buttons.scss +5 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_confirm-page.scss +20 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_lists.scss +5 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_progressive-reveal.scss +17 -0
- package/package/frontend/toolkit/assets/stylesheets/modules/_validation.scss +51 -0
- package/package/frontend/toolkit/index.js +10 -0
- package/package/index.js +351 -0
- package/package/lib/deindex.js +18 -0
- package/package/lib/encryption.js +23 -0
- package/package/lib/ga-tag.js +89 -0
- package/package/lib/health.js +26 -0
- package/package/lib/helpers.js +66 -0
- package/package/lib/logger.js +65 -0
- package/package/lib/markdown.js +46 -0
- package/package/lib/router.js +111 -0
- package/package/lib/serve-static.js +12 -0
- package/package/lib/sessions.js +82 -0
- package/package/lib/settings.js +74 -0
- package/package/lib/which.js +28 -0
- package/package/middleware/cookies.js +43 -0
- package/package/middleware/deep-translate.js +32 -0
- package/package/middleware/errors.js +119 -0
- package/package/middleware/index.js +10 -0
- package/package/middleware/not-found.js +38 -0
- package/package/middleware/rate-limiter.js +98 -0
- package/package/middleware/service-unavailable.js +64 -0
- package/package/model/apis/axios-settings.js +21 -0
- package/package/model/apis/html-to-pdf-converter.js +35 -0
- package/package/model/apis/index.js +5 -0
- package/package/model/index.js +348 -0
- package/package/package.json +147 -0
- package/package/sandbox/README.md +66 -0
- package/package/sandbox/apps/sandbox/behaviours/clear-session.js +8 -0
- package/package/sandbox/apps/sandbox/behaviours/country-select.js +10 -0
- package/package/sandbox/apps/sandbox/behaviours/international-number.js +22 -0
- package/package/sandbox/apps/sandbox/fields.js +128 -0
- package/package/sandbox/apps/sandbox/index.js +99 -0
- package/package/sandbox/apps/sandbox/lib/staticAppealStages.js +189 -0
- package/package/sandbox/apps/sandbox/sections/summary-data-sections.js +43 -0
- package/package/sandbox/apps/sandbox/translations/src/en/errors.json +5 -0
- package/package/sandbox/apps/sandbox/translations/src/en/exit.json +4 -0
- package/package/sandbox/apps/sandbox/translations/src/en/fields.json +101 -0
- package/package/sandbox/apps/sandbox/translations/src/en/journey.json +7 -0
- package/package/sandbox/apps/sandbox/translations/src/en/pages.json +72 -0
- package/package/sandbox/apps/sandbox/translations/src/en/validation.json +54 -0
- package/package/sandbox/apps/sandbox/views/form-guidance-link.html +8 -0
- package/package/sandbox/apps/sandbox/views/save-and-exit.html +19 -0
- package/package/sandbox/assets/images/icons/icon-caret-left.png +0 -0
- package/package/sandbox/assets/images/icons/icon-complete.png +0 -0
- package/package/sandbox/assets/images/icons/icon-cross-remove-sign.png +0 -0
- package/package/sandbox/assets/js/index.js +70 -0
- package/package/sandbox/assets/scss/app.scss +27 -0
- package/package/sandbox/codecept.conf.js +15 -0
- package/package/sandbox/config.js +17 -0
- package/package/sandbox/package.json +26 -0
- package/package/sandbox/server.js +23 -0
- package/package/sandbox/yarn.lock +262 -0
- package/package/transpiler/index.js +2 -0
- package/package/transpiler/lib/aggregate.js +32 -0
- package/package/transpiler/lib/build.js +15 -0
- package/package/transpiler/lib/compile.js +12 -0
- package/package/transpiler/lib/expand-dirs.js +14 -0
- package/package/transpiler/lib/write-files.js +24 -0
- package/package/utilities/autofill/index.js +189 -0
- package/package/utilities/autofill/inputs.js +60 -0
- package/package/utilities/countries.js +12 -0
- package/package/utilities/helpers/index.js +189 -0
- package/package/utilities/index.js +9 -0
- package/package/utilities/reqres/index.js +18 -0
- package/package/utilities/test-data/data/domain.json +7 -0
- package/package/utilities/test-data/data/firstname.json +16 -0
- package/package/utilities/test-data/data/lastname.json +10 -0
- package/package/utilities/test-data/data/postcode.json +12 -0
- package/package/utilities/test-data/data/streetname.json +8 -0
- package/package/utilities/test-data/data/streetsuffix.json +7 -0
- package/package/utilities/test-data/data/town.json +9 -0
- package/package/utilities/test-data/index.js +67 -0
- package/package/wizard/behaviours/complete.js +20 -0
- package/package/wizard/behaviours/index.js +5 -0
- package/package/wizard/index.js +124 -0
- package/package/wizard/middleware/back-links.js +68 -0
- package/package/wizard/middleware/check-complete.js +13 -0
- package/package/wizard/middleware/check-progress.js +139 -0
- package/package/wizard/middleware/check-session.js +17 -0
- package/package/wizard/middleware/csrf.js +47 -0
- package/package/wizard/middleware/session-model.js +11 -0
- package/package/wizard/middleware/session.js +9 -0
- package/package/wizard/model.js +29 -0
- package/package/wizard/util/constants.js +5 -0
- package/package/wizard/util/helpers.js +19 -0
- package/package.json +5 -6
- package/.editorconfig +0 -10
- package/.github/workflows/automate-publish.yml +0 -38
- package/.github/workflows/automate-tag.yml +0 -78
- package/.istanbul.yml +0 -20
- package/.nyc_output/be573ac3-d055-4910-a088-9d41b5345cec.json +0 -1
- package/.nyc_output/processinfo/be573ac3-d055-4910-a088-9d41b5345cec.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/codeReviewChecklist.md +0 -22
- package/pull_request_template.md +0 -16
@@ -0,0 +1,189 @@
|
|
1
|
+
/* eslint-disable no-param-reassign, consistent-return */
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
const _ = require('lodash');
|
5
|
+
const logger = require('../../lib/logger');
|
6
|
+
|
7
|
+
module.exports = class Helpers {
|
8
|
+
/**
|
9
|
+
* Utility function which returns the
|
10
|
+
* name of the step a field is present on
|
11
|
+
* @param {String} field - id of the field
|
12
|
+
* @param {Object} steps - steps config object
|
13
|
+
* @returns {String} - the key of the step where field is found
|
14
|
+
*/
|
15
|
+
static getStepFromFieldName(field, stepsConfig) {
|
16
|
+
return _.findKey(stepsConfig, step => step.fields && step.fields.indexOf(field) > -1);
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Alternative 'falsy' check which doesn't
|
21
|
+
* return false for 0 or false
|
22
|
+
* @param {any} value - the value to check
|
23
|
+
* @returns {Boolean} - if the value is 'empty'
|
24
|
+
*/
|
25
|
+
static isEmptyValue(value) {
|
26
|
+
return value === undefined || value === null || value === '';
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Helper function to lookup and return the page title
|
31
|
+
* translation if found. If not it will fallback to the
|
32
|
+
* label or legend of the first field on the page
|
33
|
+
* @param {String} route - the route of the step
|
34
|
+
* @param {Function} lookup - i18n-lookup bound to translate and Mustache.render
|
35
|
+
* @param {Object} fields - a key:value map of step fields
|
36
|
+
* @param {Object} locals - the locals map for mustache rendering
|
37
|
+
* @returns {String} - the first translation found
|
38
|
+
*/
|
39
|
+
static getTitle(route, lookup, fields, locals) {
|
40
|
+
let fieldName = '';
|
41
|
+
if (_.size(fields)) {
|
42
|
+
fieldName = Object.keys(fields)[0];
|
43
|
+
}
|
44
|
+
return lookup([
|
45
|
+
`pages.${route}.header`,
|
46
|
+
`fields.${fieldName}.label`,
|
47
|
+
`fields.${fieldName}.legend`
|
48
|
+
], locals);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Helper function to return intro if
|
53
|
+
* located in pages.{route}.intro
|
54
|
+
* @param {String} route - the route of the step
|
55
|
+
* @param {Function} lookup - i18n-lookup bound to translate and Mustache.render
|
56
|
+
* @param {Object} locals - the locals map for mustache rendering
|
57
|
+
* @returns {String} the translation if found
|
58
|
+
*/
|
59
|
+
static getIntro(route, lookup, locals) {
|
60
|
+
return lookup([
|
61
|
+
`pages.${route}.intro`
|
62
|
+
], locals);
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Utility function which returns true
|
67
|
+
* if a field type has associated options
|
68
|
+
* @param {String} mixin - the name of the mixin
|
69
|
+
* @returns {Boolean} - if the mixin has associated options
|
70
|
+
*/
|
71
|
+
static hasOptions(mixin) {
|
72
|
+
return mixin === 'radio-group' || mixin === 'checkbox-group' || mixin === 'select';
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* helper function for looking up values in
|
77
|
+
* fields that have options
|
78
|
+
* @param {Function} translate - translate function
|
79
|
+
* @param {String} field - the id of the field
|
80
|
+
* @param {String} value - the value of the field
|
81
|
+
* @returns {String} the translation of the label if found,
|
82
|
+
* the raw value if not
|
83
|
+
*/
|
84
|
+
static getValue(translate, field, values) {
|
85
|
+
if (!Array.isArray(values)) {
|
86
|
+
values = [values];
|
87
|
+
}
|
88
|
+
return values.map(value => {
|
89
|
+
const key = `fields.${field}.options.${value}.label`;
|
90
|
+
const result = translate(key);
|
91
|
+
return result === key ? value : result;
|
92
|
+
}).join('\n');
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* utility function which returns undefined on
|
97
|
+
* failed translations instead of returning the key
|
98
|
+
* @param {Function} translate - the translate function
|
99
|
+
* @param {String} key - the key to translate
|
100
|
+
* @returns {String|undefined} the string result if successful, undefined if not
|
101
|
+
*/
|
102
|
+
static conditionalTranslate(translate, key) {
|
103
|
+
const result = translate(key);
|
104
|
+
if (result !== key) {
|
105
|
+
return result;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Utility function which looks up translations with fallback values
|
111
|
+
* If the translation is for a field, it will first try fields.key.summary
|
112
|
+
* If this fails it will try fields.key.label, if this fails it will try
|
113
|
+
* fields.key.legend (radio-group and checkbox-group).
|
114
|
+
*
|
115
|
+
* If the translation is not for a field it will first try pages.key.summary,
|
116
|
+
* if this fails it will fallback to pages.keys.header.
|
117
|
+
* @param {Function} lookup - i18n lookup bound to translate
|
118
|
+
* @param {String} key - the key of the field/page
|
119
|
+
* @param {Boolean} isField - if the translation is for a field
|
120
|
+
* @return {String} the result of the translation
|
121
|
+
*/
|
122
|
+
static getTranslation(lookup, key, isField) {
|
123
|
+
if (isField) {
|
124
|
+
return lookup([
|
125
|
+
`fields.${key}.summary`,
|
126
|
+
`fields.${key}.label`,
|
127
|
+
`fields.${key}.legend`
|
128
|
+
]) || key;
|
129
|
+
}
|
130
|
+
return lookup([
|
131
|
+
`pages.${key}.summary`,
|
132
|
+
`pages.${key}.header`
|
133
|
+
]) || key;
|
134
|
+
}
|
135
|
+
/**
|
136
|
+
* utility function which returns true or false on
|
137
|
+
* forks depending on whether a value exists on the page
|
138
|
+
* @param {Object} req - an http request object
|
139
|
+
* @param {Object} res - an http response object
|
140
|
+
* @param {Function|Object} condition - a field condition that is either a function or object
|
141
|
+
* @returns {Boolean} the boolean result of whether a field value is set on the page or session for a fork
|
142
|
+
*/
|
143
|
+
static isFieldValueInPageOrSessionValid(req, res, condition) {
|
144
|
+
return _.isFunction(condition) ?
|
145
|
+
condition(req, res) :
|
146
|
+
condition.value === (req.form.values[condition.field] ||
|
147
|
+
(!Object.keys(req.form.values).includes(condition.field) &&
|
148
|
+
_.get(req, `form.historicalValues[${condition.field}]`)));
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Read an environment variable and coerce it to boolean.
|
153
|
+
*
|
154
|
+
* @param {*} rawValue The raw value (e.g. process.env.FEATURE_FLAG)
|
155
|
+
* @param {boolean} [fallback=false] Value to use if rawValue is null/undefined/invalid
|
156
|
+
* @param {string} [envVarName='ENV_VAR'] Name for log context
|
157
|
+
* @returns {boolean}
|
158
|
+
*/
|
159
|
+
static getEnvBoolean(rawValue, fallback = false, envVarName = 'ENV_VAR') {
|
160
|
+
if (typeof rawValue === 'boolean') {
|
161
|
+
return rawValue;
|
162
|
+
}
|
163
|
+
|
164
|
+
if (rawValue === null || rawValue === undefined) {
|
165
|
+
return fallback;
|
166
|
+
}
|
167
|
+
|
168
|
+
if (typeof rawValue === 'string') {
|
169
|
+
const normalized = rawValue.trim().toLowerCase();
|
170
|
+
if (normalized === 'true') {
|
171
|
+
return true;
|
172
|
+
}
|
173
|
+
if (normalized === 'false') {
|
174
|
+
return false;
|
175
|
+
}
|
176
|
+
logger.warn(
|
177
|
+
`Invalid environment variable ${envVarName} value "${rawValue}" ` +
|
178
|
+
'– must be "true" or "false"; defaulting to ' +
|
179
|
+
`${fallback}`
|
180
|
+
);
|
181
|
+
return fallback;
|
182
|
+
}
|
183
|
+
|
184
|
+
logger.warn(
|
185
|
+
`Invalid environment variable ${envVarName} type (${typeof rawValue}); defaulting to ${fallback}`
|
186
|
+
);
|
187
|
+
return fallback;
|
188
|
+
}
|
189
|
+
};
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
const reqres = require('reqres');
|
3
|
+
const Model = require('../../model');
|
4
|
+
|
5
|
+
module.exports = {
|
6
|
+
req: options => {
|
7
|
+
const opts = options || {};
|
8
|
+
const req = reqres.req(opts);
|
9
|
+
req.form = req.form || {};
|
10
|
+
req.form.values = req.form.values || {};
|
11
|
+
req.form.options = req.form.options || {};
|
12
|
+
req.sessionModel = new Model(opts.session);
|
13
|
+
req.translate = key => key;
|
14
|
+
req.log = () => {};
|
15
|
+
return req;
|
16
|
+
},
|
17
|
+
res: reqres.res
|
18
|
+
};
|
@@ -0,0 +1,67 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const countries = require('homeoffice-countries').allCountries;
|
4
|
+
|
5
|
+
const pick = set => set[Math.floor(Math.random() * set.length)];
|
6
|
+
|
7
|
+
const Data = {};
|
8
|
+
|
9
|
+
[
|
10
|
+
'firstname',
|
11
|
+
'lastname',
|
12
|
+
'streetname',
|
13
|
+
'streetsuffix',
|
14
|
+
'town',
|
15
|
+
'postcode',
|
16
|
+
'domain'
|
17
|
+
].forEach(key => {
|
18
|
+
const values = require(`./data/${key}`);
|
19
|
+
Object.defineProperty(Data, key, {
|
20
|
+
get: () => pick(values)
|
21
|
+
});
|
22
|
+
});
|
23
|
+
|
24
|
+
Object.defineProperty(Data, 'name', {
|
25
|
+
get: function () {
|
26
|
+
return `${Data.firstname} ${Data.lastname}`;
|
27
|
+
}
|
28
|
+
});
|
29
|
+
|
30
|
+
Object.defineProperty(Data, 'address', {
|
31
|
+
get: function () {
|
32
|
+
return `${Data.number(1, 100)} ${Data.streetname} ${Data.streetsuffix}, ${Data.town}, ${Data.postcode}`;
|
33
|
+
}
|
34
|
+
});
|
35
|
+
|
36
|
+
Object.defineProperty(Data, 'email', {
|
37
|
+
get: function () {
|
38
|
+
return `${Data.firstname.toLowerCase()}.${Data.lastname.toLowerCase()}@${Data.domain}`;
|
39
|
+
}
|
40
|
+
});
|
41
|
+
|
42
|
+
Object.defineProperty(Data, 'phone', {
|
43
|
+
get: function () {
|
44
|
+
const prefix = pick(['01', '07', '+44(0)7', '+44(0)1']);
|
45
|
+
return `${prefix}${Data.number(100, 999)} ${Data.number(100, 999)} ${Data.number(100, 999)}`;
|
46
|
+
}
|
47
|
+
});
|
48
|
+
|
49
|
+
Object.defineProperty(Data, 'country', {
|
50
|
+
get: () => pick(countries)
|
51
|
+
});
|
52
|
+
|
53
|
+
Data.number = (mn, mx) => {
|
54
|
+
let min = mn;
|
55
|
+
let max = mx;
|
56
|
+
|
57
|
+
if (min && max === undefined) {
|
58
|
+
max = min;
|
59
|
+
min = 0;
|
60
|
+
}
|
61
|
+
if (max === undefined) {
|
62
|
+
max = 100;
|
63
|
+
}
|
64
|
+
return min + Math.floor(Math.random() * (max - min));
|
65
|
+
};
|
66
|
+
|
67
|
+
module.exports = Data;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const constants = require('../util/constants');
|
4
|
+
|
5
|
+
module.exports = superclass => class extends superclass {
|
6
|
+
constructor(options) {
|
7
|
+
super(options);
|
8
|
+
if (options.next && options.steps && options.steps[options.next]) {
|
9
|
+
const nextOptions = options.steps[options.next];
|
10
|
+
if (typeof nextOptions.allowPostComplete === 'undefined') {
|
11
|
+
nextOptions.allowPostComplete = true;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
successHandler(req, res, callback) {
|
17
|
+
req.sessionModel.set(constants.APPLICATION_COMPLETE, true);
|
18
|
+
super.successHandler(req, res, callback);
|
19
|
+
}
|
20
|
+
};
|
@@ -0,0 +1,124 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const path = require('path');
|
4
|
+
const express = require('express');
|
5
|
+
const _ = require('lodash');
|
6
|
+
const deprecate = require('deprecate');
|
7
|
+
const FormController = require('../controller');
|
8
|
+
const mix = require('mixwith').mix;
|
9
|
+
|
10
|
+
const IncludedBehaviours = require('./behaviours');
|
11
|
+
|
12
|
+
let count = 0;
|
13
|
+
|
14
|
+
const getController = (SuperClass, behavs) => {
|
15
|
+
let behaviours = behavs ? _.castArray(behavs) : [];
|
16
|
+
if (!behaviours.length) {
|
17
|
+
return SuperClass;
|
18
|
+
}
|
19
|
+
behaviours = behaviours.map(behaviour => typeof behaviour === 'string' ? IncludedBehaviours[behaviour] : behaviour);
|
20
|
+
/*
|
21
|
+
* This class declaration could be better written using
|
22
|
+
* array spread syntax, supported in node >= 5.11.0:
|
23
|
+
*
|
24
|
+
* class Controller extends mix(SuperClass).with(...behaviours) {}
|
25
|
+
*/
|
26
|
+
const _mix = mix(SuperClass);
|
27
|
+
return class extends _mix.with.apply(_mix, behaviours) {};
|
28
|
+
};
|
29
|
+
|
30
|
+
const Wizard = (steps, fields, setts) => {
|
31
|
+
const settings = Object.assign({
|
32
|
+
params: '/:action?',
|
33
|
+
controller: FormController
|
34
|
+
}, setts || {});
|
35
|
+
|
36
|
+
// prevent potentially conflicting session namespaces
|
37
|
+
if (!settings.name) {
|
38
|
+
settings.name = count;
|
39
|
+
count++;
|
40
|
+
}
|
41
|
+
|
42
|
+
settings.name = `hof-wizard-${settings.name}`;
|
43
|
+
settings.formatters = settings.formatters || ['trim', 'singlespaces', 'hyphens'];
|
44
|
+
|
45
|
+
const app = express.Router();
|
46
|
+
|
47
|
+
app.use(require('./middleware/session'));
|
48
|
+
|
49
|
+
let first;
|
50
|
+
|
51
|
+
if (!steps['/']) {
|
52
|
+
app.get('/', (req, res) => {
|
53
|
+
res.redirect(path.join(req.baseUrl, first));
|
54
|
+
});
|
55
|
+
}
|
56
|
+
|
57
|
+
_.each(steps, (opts, route) => {
|
58
|
+
first = first || route;
|
59
|
+
|
60
|
+
const options = _.cloneDeep(opts);
|
61
|
+
|
62
|
+
options.fields = (options.fields || []).reduce((obj, field) => {
|
63
|
+
obj[field] = fields[field] || {};
|
64
|
+
return obj;
|
65
|
+
}, {});
|
66
|
+
options.steps = steps;
|
67
|
+
options.route = route;
|
68
|
+
options.appConfig = settings.appConfig;
|
69
|
+
options.confirmStep = settings.confirmStep;
|
70
|
+
options.exitStep = settings.exitStep;
|
71
|
+
options.saveAndExitStep = settings.saveAndExitStep;
|
72
|
+
options.clearSession = options.clearSession || false;
|
73
|
+
options.fieldsConfig = _.cloneDeep(fields);
|
74
|
+
options.sanitiseInputs = settings.sanitiseInputs;
|
75
|
+
|
76
|
+
options.defaultFormatters = [].concat(settings.formatters);
|
77
|
+
|
78
|
+
// default template is the same as the pathname
|
79
|
+
options.template = options.template || route.replace(/^\//, '');
|
80
|
+
if (settings.templatePath) {
|
81
|
+
options.template = settings.templatePath + '/' + options.template;
|
82
|
+
}
|
83
|
+
|
84
|
+
options.i18n = settings.i18n;
|
85
|
+
|
86
|
+
if (options.controller) {
|
87
|
+
deprecate(
|
88
|
+
'hof-form-wizard: Passing a custom step controller is deprecated',
|
89
|
+
'Instead give one or more behaviours which will be mixed in to the base controller'
|
90
|
+
);
|
91
|
+
}
|
92
|
+
|
93
|
+
const SuperClass = options.controller || settings.controller;
|
94
|
+
const Controller = getController(SuperClass, options.behaviours);
|
95
|
+
const controller = new Controller(options);
|
96
|
+
|
97
|
+
controller.use([
|
98
|
+
require('./middleware/check-session')(route, controller, steps, first, settings),
|
99
|
+
require('./middleware/check-complete')(route, controller, steps, first),
|
100
|
+
require('./middleware/check-progress')(route, controller, steps, first)
|
101
|
+
]);
|
102
|
+
if (settings.csrf !== false) {
|
103
|
+
controller.use(require('./middleware/csrf')(route, controller, steps, first));
|
104
|
+
}
|
105
|
+
|
106
|
+
app.route(route + settings.params)
|
107
|
+
.all((req, res, next) => {
|
108
|
+
if (settings.translate) {
|
109
|
+
req.translate = settings.translate;
|
110
|
+
}
|
111
|
+
next();
|
112
|
+
})
|
113
|
+
.all(require('./middleware/session-model')(settings))
|
114
|
+
.all(require('./middleware/back-links')(route, controller, steps, first))
|
115
|
+
.all(controller.requestHandler());
|
116
|
+
});
|
117
|
+
|
118
|
+
return app;
|
119
|
+
};
|
120
|
+
|
121
|
+
Wizard.Controller = FormController;
|
122
|
+
Wizard.Error = FormController.Error;
|
123
|
+
|
124
|
+
module.exports = Wizard;
|
@@ -0,0 +1,68 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const path = require('path');
|
4
|
+
const _ = require('lodash');
|
5
|
+
const helpers = require('../util/helpers');
|
6
|
+
|
7
|
+
module.exports = (route, controller, steps) => {
|
8
|
+
const previousSteps = helpers.getRouteSteps(route, steps);
|
9
|
+
|
10
|
+
const checkReferrer = (referrer, baseUrl) => {
|
11
|
+
const referrerPath = new URL(referrer).pathname;
|
12
|
+
const matchingPath = controller.options.backLinks.find(link => {
|
13
|
+
if (link.match(/^\//)) {
|
14
|
+
return path.normalize(link) === referrerPath;
|
15
|
+
} else if (path.relative(baseUrl, referrerPath)) {
|
16
|
+
return path.normalize(link) === path.relative(baseUrl, referrerPath);
|
17
|
+
} else if (referrerPath.replace(/^\//, '') === link.replace(/^\.*\//, '')) {
|
18
|
+
return path.normalize(link);
|
19
|
+
}
|
20
|
+
return undefined;
|
21
|
+
});
|
22
|
+
if (typeof matchingPath === 'string') {
|
23
|
+
return path.normalize(matchingPath);
|
24
|
+
}
|
25
|
+
return undefined;
|
26
|
+
};
|
27
|
+
|
28
|
+
const checkFormHistory = sessionData => {
|
29
|
+
const prev = _(sessionData)
|
30
|
+
.pickBy((value, key) => key.indexOf('hof-wizard') > -1)
|
31
|
+
.map('steps')
|
32
|
+
.flatten()
|
33
|
+
.uniq()
|
34
|
+
.value();
|
35
|
+
|
36
|
+
const allowedLinks = controller.options.backLinks.map(item =>
|
37
|
+
item.replace('\.', '')
|
38
|
+
);
|
39
|
+
|
40
|
+
const backLinks = _.intersection(prev, allowedLinks);
|
41
|
+
|
42
|
+
return backLinks.length ? _.last(backLinks).replace(/^\//, '') : undefined;
|
43
|
+
};
|
44
|
+
|
45
|
+
const getBackLink = req => {
|
46
|
+
const previous = _.intersection(req.sessionModel.get('steps'), previousSteps);
|
47
|
+
let backLink;
|
48
|
+
|
49
|
+
if (typeof controller.options.backLink !== 'undefined') {
|
50
|
+
return controller.options.backLink;
|
51
|
+
} else if (previous.length) {
|
52
|
+
backLink = req.baseUrl === '/' ? _.last(previous) : _.last(previous).replace(/^\//, '');
|
53
|
+
} else if (controller.options.backLinks && req.get('referrer')) {
|
54
|
+
backLink = checkReferrer(req.get('referrer'), req.baseUrl) || checkFormHistory(req.session);
|
55
|
+
}
|
56
|
+
|
57
|
+
return backLink;
|
58
|
+
};
|
59
|
+
|
60
|
+
return (req, res, next) => {
|
61
|
+
if (req.method === 'GET') {
|
62
|
+
const last = _.last(req.sessionModel.get('steps'));
|
63
|
+
req.isBackLink = (last === route || last === controller.options.next);
|
64
|
+
res.locals.backLink = getBackLink(req);
|
65
|
+
}
|
66
|
+
next();
|
67
|
+
};
|
68
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const constants = require('../util/constants');
|
4
|
+
const path = require('path');
|
5
|
+
|
6
|
+
module.exports = (route, controller, steps, start) => (req, res, next) => {
|
7
|
+
if (req.sessionModel.get(constants.APPLICATION_COMPLETE) && !controller.options.allowPostComplete) {
|
8
|
+
req.sessionModel.reset();
|
9
|
+
res.redirect(path.join(req.baseUrl, start));
|
10
|
+
return;
|
11
|
+
}
|
12
|
+
next();
|
13
|
+
};
|