@defra/forms-engine-plugin 0.0.1
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/.browserslistrc +16 -0
- package/.editorconfig +9 -0
- package/.eslintrc.cjs +266 -0
- package/.github/dependabot.yml +85 -0
- package/.github/workflows/check-pull-request.yml +209 -0
- package/.github/workflows/pr-notifier.yml +98 -0
- package/.github/workflows/publish.yml +111 -0
- package/.husky/pre-commit +1 -0
- package/.lintstagedrc.js +4 -0
- package/.nvmrc +1 -0
- package/.prettierignore +8 -0
- package/.prettierrc.cjs +26 -0
- package/.server/client/javascripts/application.js +68 -0
- package/.server/client/javascripts/application.js.map +1 -0
- package/.server/client/javascripts/file-upload.js +292 -0
- package/.server/client/javascripts/file-upload.js.map +1 -0
- package/.server/client/stylesheets/_code.scss +33 -0
- package/.server/client/stylesheets/_govuk-frontend.scss +4 -0
- package/.server/client/stylesheets/_prose.scss +56 -0
- package/.server/client/stylesheets/_service-banner.scss +24 -0
- package/.server/client/stylesheets/_summary-list.scss +28 -0
- package/.server/client/stylesheets/_tag-env.scss +24 -0
- package/.server/client/stylesheets/application.scss +14 -0
- package/.server/common/cookies.js +55 -0
- package/.server/common/cookies.js.map +1 -0
- package/.server/common/cookies.test.js +15 -0
- package/.server/common/cookies.test.js.map +1 -0
- package/.server/common/types.js +6 -0
- package/.server/common/types.js.map +1 -0
- package/.server/config/index.js +241 -0
- package/.server/config/index.js.map +1 -0
- package/.server/index.js +25 -0
- package/.server/index.js.map +1 -0
- package/.server/server/common/helpers/logging/logger-options.js +44 -0
- package/.server/server/common/helpers/logging/logger-options.js.map +1 -0
- package/.server/server/common/helpers/logging/logger.js +6 -0
- package/.server/server/common/helpers/logging/logger.js.map +1 -0
- package/.server/server/common/helpers/logging/request-logger.js +7 -0
- package/.server/server/common/helpers/logging/request-logger.js.map +1 -0
- package/.server/server/common/helpers/logging/request-tracing.js +12 -0
- package/.server/server/common/helpers/logging/request-tracing.js.map +1 -0
- package/.server/server/common/helpers/redis-client.js +55 -0
- package/.server/server/common/helpers/redis-client.js.map +1 -0
- package/.server/server/constants.js +2 -0
- package/.server/server/constants.js.map +1 -0
- package/.server/server/forms/README.md +10 -0
- package/.server/server/forms/components.json +1015 -0
- package/.server/server/forms/report-a-terrorist.json +270 -0
- package/.server/server/forms/runner-components-test.json +365 -0
- package/.server/server/forms/test.json +581 -0
- package/.server/server/index.js +116 -0
- package/.server/server/index.js.map +1 -0
- package/.server/server/plugins/blankie.js +29 -0
- package/.server/server/plugins/blankie.js.map +1 -0
- package/.server/server/plugins/crumb.js +15 -0
- package/.server/server/plugins/crumb.js.map +1 -0
- package/.server/server/plugins/engine/README.md +87 -0
- package/.server/server/plugins/engine/components/AutocompleteField.js +37 -0
- package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -0
- package/.server/server/plugins/engine/components/CheckboxesField.js +79 -0
- package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -0
- package/.server/server/plugins/engine/components/ComponentBase.js +55 -0
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -0
- package/.server/server/plugins/engine/components/ComponentCollection.js +198 -0
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -0
- package/.server/server/plugins/engine/components/DatePartsField.js +208 -0
- package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -0
- package/.server/server/plugins/engine/components/Details.js +26 -0
- package/.server/server/plugins/engine/components/Details.js.map +1 -0
- package/.server/server/plugins/engine/components/EmailAddressField.js +40 -0
- package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -0
- package/.server/server/plugins/engine/components/FileUploadField.js +195 -0
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -0
- package/.server/server/plugins/engine/components/FormComponent.js +210 -0
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -0
- package/.server/server/plugins/engine/components/Html.js +24 -0
- package/.server/server/plugins/engine/components/Html.js.map +1 -0
- package/.server/server/plugins/engine/components/InsetText.js +22 -0
- package/.server/server/plugins/engine/components/InsetText.js.map +1 -0
- package/.server/server/plugins/engine/components/List.js +65 -0
- package/.server/server/plugins/engine/components/List.js.map +1 -0
- package/.server/server/plugins/engine/components/ListFormComponent.js +87 -0
- package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -0
- package/.server/server/plugins/engine/components/MonthYearField.js +172 -0
- package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -0
- package/.server/server/plugins/engine/components/MultilineTextField.js +115 -0
- package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -0
- package/.server/server/plugins/engine/components/NumberField.js +137 -0
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -0
- package/.server/server/plugins/engine/components/RadiosField.js +18 -0
- package/.server/server/plugins/engine/components/RadiosField.js.map +1 -0
- package/.server/server/plugins/engine/components/SelectField.js +33 -0
- package/.server/server/plugins/engine/components/SelectField.js.map +1 -0
- package/.server/server/plugins/engine/components/SelectionControlField.js +43 -0
- package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -0
- package/.server/server/plugins/engine/components/TelephoneNumberField.js +43 -0
- package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -0
- package/.server/server/plugins/engine/components/TextField.js +63 -0
- package/.server/server/plugins/engine/components/TextField.js.map +1 -0
- package/.server/server/plugins/engine/components/UkAddressField.js +130 -0
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -0
- package/.server/server/plugins/engine/components/YesNoField.js +28 -0
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -0
- package/.server/server/plugins/engine/components/constants.js +2 -0
- package/.server/server/plugins/engine/components/constants.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers.js +219 -0
- package/.server/server/plugins/engine/components/helpers.js.map +1 -0
- package/.server/server/plugins/engine/components/index.js +25 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -0
- package/.server/server/plugins/engine/components/types.js +2 -0
- package/.server/server/plugins/engine/components/types.js.map +1 -0
- package/.server/server/plugins/engine/configureEnginePlugin.js +44 -0
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -0
- package/.server/server/plugins/engine/helpers.js +268 -0
- package/.server/server/plugins/engine/helpers.js.map +1 -0
- package/.server/server/plugins/engine/index.js +6 -0
- package/.server/server/plugins/engine/index.js.map +1 -0
- package/.server/server/plugins/engine/models/FormModel.js +363 -0
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -0
- package/.server/server/plugins/engine/models/RepeatingSummaryViewModel.js +2 -0
- package/.server/server/plugins/engine/models/RepeatingSummaryViewModel.js.map +1 -0
- package/.server/server/plugins/engine/models/Section.js +2 -0
- package/.server/server/plugins/engine/models/Section.js.map +1 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.js +183 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -0
- package/.server/server/plugins/engine/models/index.js +3 -0
- package/.server/server/plugins/engine/models/index.js.map +1 -0
- package/.server/server/plugins/engine/models/types.js +2 -0
- package/.server/server/plugins/engine/models/types.js.map +1 -0
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +44 -0
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -0
- package/.server/server/plugins/engine/outputFormatters/index.js +24 -0
- package/.server/server/plugins/engine/outputFormatters/index.js.map +1 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js +104 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +110 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +401 -0
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/PageController.js +133 -0
- package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +482 -0
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/README.md +28 -0
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +372 -0
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/StartPageController.js +16 -0
- package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js +43 -0
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +195 -0
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/TerminalPageController.js +8 -0
- package/.server/server/plugins/engine/pageControllers/TerminalPageController.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/helpers.js +69 -0
- package/.server/server/plugins/engine/pageControllers/helpers.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/index.js +10 -0
- package/.server/server/plugins/engine/pageControllers/index.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +78 -0
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -0
- package/.server/server/plugins/engine/plugin.js +562 -0
- package/.server/server/plugins/engine/plugin.js.map +1 -0
- package/.server/server/plugins/engine/services/formSubmissionService.js +39 -0
- package/.server/server/plugins/engine/services/formSubmissionService.js.map +1 -0
- package/.server/server/plugins/engine/services/formsService.js +41 -0
- package/.server/server/plugins/engine/services/formsService.js.map +1 -0
- package/.server/server/plugins/engine/services/formsService.test.js +71 -0
- package/.server/server/plugins/engine/services/formsService.test.js.map +1 -0
- package/.server/server/plugins/engine/services/index.js +4 -0
- package/.server/server/plugins/engine/services/index.js.map +1 -0
- package/.server/server/plugins/engine/services/notifyService.js +45 -0
- package/.server/server/plugins/engine/services/notifyService.js.map +1 -0
- package/.server/server/plugins/engine/services/uploadService.js +51 -0
- package/.server/server/plugins/engine/services/uploadService.js.map +1 -0
- package/.server/server/plugins/engine/types.js +53 -0
- package/.server/server/plugins/engine/types.js.map +1 -0
- package/.server/server/plugins/engine/views/components/autocompletefield.html +5 -0
- package/.server/server/plugins/engine/views/components/checkboxesfield.html +5 -0
- package/.server/server/plugins/engine/views/components/datepartsfield.html +5 -0
- package/.server/server/plugins/engine/views/components/details.html +6 -0
- package/.server/server/plugins/engine/views/components/emailaddressfield.html +5 -0
- package/.server/server/plugins/engine/views/components/fileuploadfield-key.html +8 -0
- package/.server/server/plugins/engine/views/components/fileuploadfield-value.html +3 -0
- package/.server/server/plugins/engine/views/components/fileuploadfield.html +24 -0
- package/.server/server/plugins/engine/views/components/html.html +3 -0
- package/.server/server/plugins/engine/views/components/insettext.html +7 -0
- package/.server/server/plugins/engine/views/components/list.html +36 -0
- package/.server/server/plugins/engine/views/components/monthyearfield.html +5 -0
- package/.server/server/plugins/engine/views/components/multilinetextfield.html +10 -0
- package/.server/server/plugins/engine/views/components/numberfield.html +5 -0
- package/.server/server/plugins/engine/views/components/radiosfield.html +5 -0
- package/.server/server/plugins/engine/views/components/selectfield.html +5 -0
- package/.server/server/plugins/engine/views/components/telephonenumberfield.html +5 -0
- package/.server/server/plugins/engine/views/components/textfield.html +5 -0
- package/.server/server/plugins/engine/views/components/ukaddressfield.html +25 -0
- package/.server/server/plugins/engine/views/components/yesnofield.html +5 -0
- package/.server/server/plugins/engine/views/file-upload.html +45 -0
- package/.server/server/plugins/engine/views/index.html +39 -0
- package/.server/server/plugins/engine/views/item-delete.html +56 -0
- package/.server/server/plugins/engine/views/partials/components.html +6 -0
- package/.server/server/plugins/engine/views/partials/conditional-components.html +3 -0
- package/.server/server/plugins/engine/views/partials/debug.html +44 -0
- package/.server/server/plugins/engine/views/partials/form.html +15 -0
- package/.server/server/plugins/engine/views/partials/heading.html +16 -0
- package/.server/server/plugins/engine/views/partials/preview-banner.html +32 -0
- package/.server/server/plugins/engine/views/partials/preview-banner.test.js +108 -0
- package/.server/server/plugins/engine/views/partials/preview-banner.test.js.map +1 -0
- package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +10 -0
- package/.server/server/plugins/engine/views/repeat-list-summary.html +53 -0
- package/.server/server/plugins/errorPages.js +49 -0
- package/.server/server/plugins/errorPages.js.map +1 -0
- package/.server/server/plugins/nunjucks/context.js +79 -0
- package/.server/server/plugins/nunjucks/context.js.map +1 -0
- package/.server/server/plugins/nunjucks/context.test.js +134 -0
- package/.server/server/plugins/nunjucks/context.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/enviroment.test.js +166 -0
- package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/environment.js +95 -0
- package/.server/server/plugins/nunjucks/environment.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/answer.js +26 -0
- package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/answer.test.js +70 -0
- package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/evaluate.js +22 -0
- package/.server/server/plugins/nunjucks/filters/evaluate.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/field.js +26 -0
- package/.server/server/plugins/nunjucks/filters/field.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/field.test.js +64 -0
- package/.server/server/plugins/nunjucks/filters/field.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/highlight.js +14 -0
- package/.server/server/plugins/nunjucks/filters/highlight.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/href.js +28 -0
- package/.server/server/plugins/nunjucks/filters/href.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/href.test.js +63 -0
- package/.server/server/plugins/nunjucks/filters/href.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js +9 -0
- package/.server/server/plugins/nunjucks/filters/index.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/inspect.js +16 -0
- package/.server/server/plugins/nunjucks/filters/inspect.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/page.js +23 -0
- package/.server/server/plugins/nunjucks/filters/page.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/page.test.js +51 -0
- package/.server/server/plugins/nunjucks/filters/page.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/index.js +4 -0
- package/.server/server/plugins/nunjucks/index.js.map +1 -0
- package/.server/server/plugins/nunjucks/plugin.js +38 -0
- package/.server/server/plugins/nunjucks/plugin.js.map +1 -0
- package/.server/server/plugins/nunjucks/render.js +41 -0
- package/.server/server/plugins/nunjucks/render.js.map +1 -0
- package/.server/server/plugins/nunjucks/types.js +41 -0
- package/.server/server/plugins/nunjucks/types.js.map +1 -0
- package/.server/server/plugins/pulse.js +8 -0
- package/.server/server/plugins/pulse.js.map +1 -0
- package/.server/server/plugins/router.js +169 -0
- package/.server/server/plugins/router.js.map +1 -0
- package/.server/server/plugins/session.js +28 -0
- package/.server/server/plugins/session.js.map +1 -0
- package/.server/server/routes/health.js +15 -0
- package/.server/server/routes/health.js.map +1 -0
- package/.server/server/routes/health.test.js +32 -0
- package/.server/server/routes/health.test.js.map +1 -0
- package/.server/server/routes/index.js +3 -0
- package/.server/server/routes/index.js.map +1 -0
- package/.server/server/routes/public.js +37 -0
- package/.server/server/routes/public.js.map +1 -0
- package/.server/server/routes/types.js +14 -0
- package/.server/server/routes/types.js.map +1 -0
- package/.server/server/schemas/index.js +15 -0
- package/.server/server/schemas/index.js.map +1 -0
- package/.server/server/secure-context.js +36 -0
- package/.server/server/secure-context.js.map +1 -0
- package/.server/server/services/cacheService.js +85 -0
- package/.server/server/services/cacheService.js.map +1 -0
- package/.server/server/services/httpService.js +44 -0
- package/.server/server/services/httpService.js.map +1 -0
- package/.server/server/services/httpService.test.js +504 -0
- package/.server/server/services/httpService.test.js.map +1 -0
- package/.server/server/services/index.js +2 -0
- package/.server/server/services/index.js.map +1 -0
- package/.server/server/types.js +2 -0
- package/.server/server/types.js.map +1 -0
- package/.server/server/utils/notify.js +40 -0
- package/.server/server/utils/notify.js.map +1 -0
- package/.server/server/utils/secure-context/get-trust-store-certs.js +7 -0
- package/.server/server/utils/secure-context/get-trust-store-certs.js.map +1 -0
- package/.server/server/utils/secure-context/get-trust-store-certs.test.js +14 -0
- package/.server/server/utils/secure-context/get-trust-store-certs.test.js.map +1 -0
- package/.server/server/utils/utils.js +20 -0
- package/.server/server/utils/utils.js.map +1 -0
- package/.server/server/utils/utils.test.js +49 -0
- package/.server/server/utils/utils.test.js.map +1 -0
- package/.server/server/views/404.html +16 -0
- package/.server/server/views/500.html +19 -0
- package/.server/server/views/components/debug/macro.njk +3 -0
- package/.server/server/views/components/debug/template.njk +13 -0
- package/.server/server/views/components/service-banner/macro.njk +3 -0
- package/.server/server/views/components/service-banner/template.njk +20 -0
- package/.server/server/views/components/service-banner/template.test.js +36 -0
- package/.server/server/views/components/service-banner/template.test.js.map +1 -0
- package/.server/server/views/components/tag-env/macro.njk +3 -0
- package/.server/server/views/components/tag-env/template.njk +30 -0
- package/.server/server/views/components/tag-env/template.test.js +59 -0
- package/.server/server/views/components/tag-env/template.test.js.map +1 -0
- package/.server/server/views/confirmation.html +19 -0
- package/.server/server/views/help/accessibility-statement.html +58 -0
- package/.server/server/views/help/cookie-preferences.html +57 -0
- package/.server/server/views/help/cookies.html +71 -0
- package/.server/server/views/help/get-support.html +37 -0
- package/.server/server/views/help/privacy-notice.html +68 -0
- package/.server/server/views/help/terms-and-conditions.html +83 -0
- package/.server/server/views/layout.html +199 -0
- package/.server/server/views/summary.html +50 -0
- package/.server/typings/hapi/index.d.js +2 -0
- package/.server/typings/hapi/index.d.js.map +1 -0
- package/.server/typings/hapi-tracing/index.d.js +2 -0
- package/.server/typings/hapi-tracing/index.d.js.map +1 -0
- package/.server/typings/index.d.js +2 -0
- package/.server/typings/index.d.js.map +1 -0
- package/.server/typings/joi/index.d.js +2 -0
- package/.server/typings/joi/index.d.js.map +1 -0
- package/Dockerfile +61 -0
- package/LICENCE +8 -0
- package/Procfile +1 -0
- package/README.md +87 -0
- package/babel.config.cjs +55 -0
- package/compose/aws.env +4 -0
- package/compose/start-localstack.sh +26 -0
- package/docker-compose.yaml +86 -0
- package/globals.d.ts +1 -0
- package/jest.config.cjs +54 -0
- package/jest.environment.js +4 -0
- package/jest.setup.cjs +14 -0
- package/package.json +163 -0
- package/postcss.config.js +26 -0
- package/sonar-project.properties +17 -0
- package/src/client/javascripts/application.js +87 -0
- package/src/client/javascripts/file-upload.js +386 -0
- package/src/client/stylesheets/_code.scss +33 -0
- package/src/client/stylesheets/_govuk-frontend.scss +4 -0
- package/src/client/stylesheets/_prose.scss +56 -0
- package/src/client/stylesheets/_service-banner.scss +24 -0
- package/src/client/stylesheets/_summary-list.scss +28 -0
- package/src/client/stylesheets/_tag-env.scss +24 -0
- package/src/client/stylesheets/application.scss +14 -0
- package/src/common/cookies.js +58 -0
- package/src/common/cookies.test.js +23 -0
- package/src/common/types.js +5 -0
- package/src/config/index.ts +271 -0
- package/src/index.ts +31 -0
- package/src/server/common/helpers/logging/logger-options.test.ts +50 -0
- package/src/server/common/helpers/logging/logger-options.ts +46 -0
- package/src/server/common/helpers/logging/logger.ts +7 -0
- package/src/server/common/helpers/logging/request-logger.ts +9 -0
- package/src/server/common/helpers/logging/request-tracing.js +10 -0
- package/src/server/common/helpers/redis-client.js +70 -0
- package/src/server/constants.js +1 -0
- package/src/server/forms/README.md +10 -0
- package/src/server/forms/components.json +1015 -0
- package/src/server/forms/report-a-terrorist.json +270 -0
- package/src/server/forms/runner-components-test.json +365 -0
- package/src/server/forms/test.json +581 -0
- package/src/server/index.test.ts +582 -0
- package/src/server/index.ts +140 -0
- package/src/server/plugins/blankie.test.ts +73 -0
- package/src/server/plugins/blankie.ts +48 -0
- package/src/server/plugins/crumb.ts +20 -0
- package/src/server/plugins/engine/README.md +87 -0
- package/src/server/plugins/engine/components/AutocompleteField.test.ts +294 -0
- package/src/server/plugins/engine/components/AutocompleteField.ts +49 -0
- package/src/server/plugins/engine/components/CheckboxesField.test.ts +379 -0
- package/src/server/plugins/engine/components/CheckboxesField.ts +106 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +97 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +278 -0
- package/src/server/plugins/engine/components/DatePartsField.test.ts +822 -0
- package/src/server/plugins/engine/components/DatePartsField.ts +264 -0
- package/src/server/plugins/engine/components/Details.test.ts +49 -0
- package/src/server/plugins/engine/components/Details.ts +30 -0
- package/src/server/plugins/engine/components/EmailAddressField.test.ts +395 -0
- package/src/server/plugins/engine/components/EmailAddressField.ts +55 -0
- package/src/server/plugins/engine/components/FileUploadField.test.ts +778 -0
- package/src/server/plugins/engine/components/FileUploadField.ts +262 -0
- package/src/server/plugins/engine/components/FormComponent.ts +249 -0
- package/src/server/plugins/engine/components/Html.test.ts +48 -0
- package/src/server/plugins/engine/components/Html.ts +29 -0
- package/src/server/plugins/engine/components/InsetText.test.ts +48 -0
- package/src/server/plugins/engine/components/InsetText.ts +27 -0
- package/src/server/plugins/engine/components/List.test.ts +76 -0
- package/src/server/plugins/engine/components/List.ts +72 -0
- package/src/server/plugins/engine/components/ListFormComponent.ts +140 -0
- package/src/server/plugins/engine/components/MonthYearField.test.ts +567 -0
- package/src/server/plugins/engine/components/MonthYearField.ts +222 -0
- package/src/server/plugins/engine/components/MultilineTextField.test.ts +558 -0
- package/src/server/plugins/engine/components/MultilineTextField.ts +138 -0
- package/src/server/plugins/engine/components/NumberField.test.ts +701 -0
- package/src/server/plugins/engine/components/NumberField.ts +163 -0
- package/src/server/plugins/engine/components/RadiosField.test.ts +288 -0
- package/src/server/plugins/engine/components/RadiosField.ts +24 -0
- package/src/server/plugins/engine/components/SelectField.test.ts +288 -0
- package/src/server/plugins/engine/components/SelectField.ts +47 -0
- package/src/server/plugins/engine/components/SelectionControlField.ts +43 -0
- package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +356 -0
- package/src/server/plugins/engine/components/TelephoneNumberField.ts +67 -0
- package/src/server/plugins/engine/components/TextField.test.ts +489 -0
- package/src/server/plugins/engine/components/TextField.ts +96 -0
- package/src/server/plugins/engine/components/UkAddressField.test.ts +623 -0
- package/src/server/plugins/engine/components/UkAddressField.ts +172 -0
- package/src/server/plugins/engine/components/YesNoField.test.ts +248 -0
- package/src/server/plugins/engine/components/YesNoField.ts +31 -0
- package/src/server/plugins/engine/components/constants.ts +1 -0
- package/src/server/plugins/engine/components/helpers.ts +330 -0
- package/src/server/plugins/engine/components/index.ts +24 -0
- package/src/server/plugins/engine/components/types.ts +117 -0
- package/src/server/plugins/engine/configureEnginePlugin.ts +47 -0
- package/src/server/plugins/engine/helpers.test.ts +791 -0
- package/src/server/plugins/engine/helpers.ts +379 -0
- package/src/server/plugins/engine/index.ts +7 -0
- package/src/server/plugins/engine/models/FormModel.test.ts +42 -0
- package/src/server/plugins/engine/models/FormModel.ts +443 -0
- package/src/server/plugins/engine/models/RepeatingSummaryViewModel.ts +0 -0
- package/src/server/plugins/engine/models/Section.ts +0 -0
- package/src/server/plugins/engine/models/SummaryViewModel.test.ts +209 -0
- package/src/server/plugins/engine/models/SummaryViewModel.ts +220 -0
- package/src/server/plugins/engine/models/index.ts +2 -0
- package/src/server/plugins/engine/models/types.ts +114 -0
- package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +143 -0
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +73 -0
- package/src/server/plugins/engine/outputFormatters/index.test.ts +17 -0
- package/src/server/plugins/engine/outputFormatters/index.ts +44 -0
- package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +229 -0
- package/src/server/plugins/engine/outputFormatters/machine/v1.ts +140 -0
- package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +229 -0
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +153 -0
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1108 -0
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +446 -0
- package/src/server/plugins/engine/pageControllers/PageController.test.ts +205 -0
- package/src/server/plugins/engine/pageControllers/PageController.ts +176 -0
- package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +1264 -0
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +561 -0
- package/src/server/plugins/engine/pageControllers/README.md +28 -0
- package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +264 -0
- package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +458 -0
- package/src/server/plugins/engine/pageControllers/StartPageController.ts +18 -0
- package/src/server/plugins/engine/pageControllers/StatusPageController.ts +50 -0
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +261 -0
- package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +28 -0
- package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +19 -0
- package/src/server/plugins/engine/pageControllers/helpers.test.ts +198 -0
- package/src/server/plugins/engine/pageControllers/helpers.ts +101 -0
- package/src/server/plugins/engine/pageControllers/index.ts +10 -0
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +89 -0
- package/src/server/plugins/engine/plugin.ts +673 -0
- package/src/server/plugins/engine/services/formSubmissionService.js +46 -0
- package/src/server/plugins/engine/services/formsService.js +46 -0
- package/src/server/plugins/engine/services/formsService.test.js +90 -0
- package/src/server/plugins/engine/services/index.js +3 -0
- package/src/server/plugins/engine/services/notifyService.test.ts +132 -0
- package/src/server/plugins/engine/services/notifyService.ts +64 -0
- package/src/server/plugins/engine/services/uploadService.js +60 -0
- package/src/server/plugins/engine/types.ts +315 -0
- package/src/server/plugins/engine/views/components/autocompletefield.html +5 -0
- package/src/server/plugins/engine/views/components/checkboxesfield.html +5 -0
- package/src/server/plugins/engine/views/components/datepartsfield.html +5 -0
- package/src/server/plugins/engine/views/components/details.html +6 -0
- package/src/server/plugins/engine/views/components/emailaddressfield.html +5 -0
- package/src/server/plugins/engine/views/components/fileuploadfield-key.html +8 -0
- package/src/server/plugins/engine/views/components/fileuploadfield-value.html +3 -0
- package/src/server/plugins/engine/views/components/fileuploadfield.html +24 -0
- package/src/server/plugins/engine/views/components/html.html +3 -0
- package/src/server/plugins/engine/views/components/insettext.html +7 -0
- package/src/server/plugins/engine/views/components/list.html +36 -0
- package/src/server/plugins/engine/views/components/monthyearfield.html +5 -0
- package/src/server/plugins/engine/views/components/multilinetextfield.html +10 -0
- package/src/server/plugins/engine/views/components/numberfield.html +5 -0
- package/src/server/plugins/engine/views/components/radiosfield.html +5 -0
- package/src/server/plugins/engine/views/components/selectfield.html +5 -0
- package/src/server/plugins/engine/views/components/telephonenumberfield.html +5 -0
- package/src/server/plugins/engine/views/components/textfield.html +5 -0
- package/src/server/plugins/engine/views/components/ukaddressfield.html +25 -0
- package/src/server/plugins/engine/views/components/yesnofield.html +5 -0
- package/src/server/plugins/engine/views/file-upload.html +45 -0
- package/src/server/plugins/engine/views/index.html +39 -0
- package/src/server/plugins/engine/views/item-delete.html +56 -0
- package/src/server/plugins/engine/views/partials/components.html +6 -0
- package/src/server/plugins/engine/views/partials/conditional-components.html +3 -0
- package/src/server/plugins/engine/views/partials/debug.html +44 -0
- package/src/server/plugins/engine/views/partials/form.html +15 -0
- package/src/server/plugins/engine/views/partials/heading.html +16 -0
- package/src/server/plugins/engine/views/partials/preview-banner.html +32 -0
- package/src/server/plugins/engine/views/partials/preview-banner.test.js +122 -0
- package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +10 -0
- package/src/server/plugins/engine/views/repeat-list-summary.html +53 -0
- package/src/server/plugins/errorPages.ts +58 -0
- package/src/server/plugins/nunjucks/context.js +88 -0
- package/src/server/plugins/nunjucks/context.test.js +142 -0
- package/src/server/plugins/nunjucks/enviroment.test.js +201 -0
- package/src/server/plugins/nunjucks/environment.js +116 -0
- package/src/server/plugins/nunjucks/filters/answer.js +27 -0
- package/src/server/plugins/nunjucks/filters/answer.test.js +89 -0
- package/src/server/plugins/nunjucks/filters/evaluate.js +21 -0
- package/src/server/plugins/nunjucks/filters/field.js +28 -0
- package/src/server/plugins/nunjucks/filters/field.test.js +75 -0
- package/src/server/plugins/nunjucks/filters/highlight.js +11 -0
- package/src/server/plugins/nunjucks/filters/href.js +30 -0
- package/src/server/plugins/nunjucks/filters/href.test.js +80 -0
- package/src/server/plugins/nunjucks/filters/index.js +8 -0
- package/src/server/plugins/nunjucks/filters/inspect.js +15 -0
- package/src/server/plugins/nunjucks/filters/page.js +24 -0
- package/src/server/plugins/nunjucks/filters/page.test.js +65 -0
- package/src/server/plugins/nunjucks/index.js +3 -0
- package/src/server/plugins/nunjucks/plugin.js +40 -0
- package/src/server/plugins/nunjucks/render.js +42 -0
- package/src/server/plugins/nunjucks/types.js +40 -0
- package/src/server/plugins/pulse.ts +11 -0
- package/src/server/plugins/router.ts +201 -0
- package/src/server/plugins/session.ts +28 -0
- package/src/server/routes/health.js +13 -0
- package/src/server/routes/health.test.js +35 -0
- package/src/server/routes/index.test.ts +125 -0
- package/src/server/routes/index.ts +2 -0
- package/src/server/routes/public.ts +47 -0
- package/src/server/routes/types.ts +48 -0
- package/src/server/schemas/index.ts +34 -0
- package/src/server/secure-context.js +43 -0
- package/src/server/services/cacheService.test.ts +276 -0
- package/src/server/services/cacheService.ts +131 -0
- package/src/server/services/httpService.test.js +491 -0
- package/src/server/services/httpService.ts +50 -0
- package/src/server/services/index.ts +1 -0
- package/src/server/types.ts +54 -0
- package/src/server/utils/notify.test.ts +37 -0
- package/src/server/utils/notify.ts +50 -0
- package/src/server/utils/secure-context/get-trust-store-certs.js +11 -0
- package/src/server/utils/secure-context/get-trust-store-certs.test.js +19 -0
- package/src/server/utils/utils.js +24 -0
- package/src/server/utils/utils.test.js +54 -0
- package/src/server/views/404.html +16 -0
- package/src/server/views/500.html +19 -0
- package/src/server/views/components/debug/macro.njk +3 -0
- package/src/server/views/components/debug/template.njk +13 -0
- package/src/server/views/components/service-banner/macro.njk +3 -0
- package/src/server/views/components/service-banner/template.njk +20 -0
- package/src/server/views/components/service-banner/template.test.js +43 -0
- package/src/server/views/components/tag-env/macro.njk +3 -0
- package/src/server/views/components/tag-env/template.njk +30 -0
- package/src/server/views/components/tag-env/template.test.js +66 -0
- package/src/server/views/confirmation.html +19 -0
- package/src/server/views/help/accessibility-statement.html +58 -0
- package/src/server/views/help/cookie-preferences.html +57 -0
- package/src/server/views/help/cookies.html +71 -0
- package/src/server/views/help/get-support.html +37 -0
- package/src/server/views/help/privacy-notice.html +68 -0
- package/src/server/views/help/terms-and-conditions.html +83 -0
- package/src/server/views/layout.html +199 -0
- package/src/server/views/summary.html +50 -0
- package/src/typings/hapi/index.d.ts +95 -0
- package/src/typings/hapi-tracing/index.d.ts +6 -0
- package/src/typings/index.d.ts +3 -0
- package/src/typings/joi/index.d.ts +22 -0
- package/stylelint.config.js +10 -0
- package/test/client/javascripts/file-upload.test.js +1197 -0
- package/test/condition/checkboxes.test.js +112 -0
- package/test/condition/radios.test.js +112 -0
- package/test/condition/text.test.js +103 -0
- package/test/fixtures/assets-manifest.json +4 -0
- package/test/fixtures/form.js +86 -0
- package/test/fixtures/index.js +2 -0
- package/test/fixtures/list.js +92 -0
- package/test/form/cookies.test.js +338 -0
- package/test/form/csrf.test.js +87 -0
- package/test/form/definitions/basic.js +101 -0
- package/test/form/definitions/blank.js +10 -0
- package/test/form/definitions/checkboxes.json +88 -0
- package/test/form/definitions/components.json +452 -0
- package/test/form/definitions/conditional-reveal.js +140 -0
- package/test/form/definitions/conditions-basic.js +187 -0
- package/test/form/definitions/conditions-complex.js +338 -0
- package/test/form/definitions/conditions-dates.js +78 -0
- package/test/form/definitions/conditions-escaping.js +143 -0
- package/test/form/definitions/demo-cph-number.js +3099 -0
- package/test/form/definitions/feedback.json +45 -0
- package/test/form/definitions/fields-optional.js +402 -0
- package/test/form/definitions/fields-required.js +402 -0
- package/test/form/definitions/file-upload-basic.js +44 -0
- package/test/form/definitions/file-upload.js +66 -0
- package/test/form/definitions/minimal.js +39 -0
- package/test/form/definitions/phase-alpha.json +33 -0
- package/test/form/definitions/phase-default.json +26 -0
- package/test/form/definitions/radios.json +88 -0
- package/test/form/definitions/repeat-mixed.js +54 -0
- package/test/form/definitions/repeat.js +70 -0
- package/test/form/definitions/status.json +126 -0
- package/test/form/definitions/templates.js +183 -0
- package/test/form/definitions/test.json +581 -0
- package/test/form/definitions/text.json +75 -0
- package/test/form/definitions/titles.json +170 -0
- package/test/form/definitions.test.js +47 -0
- package/test/form/exit-page.test.js +210 -0
- package/test/form/feedback.test.js +68 -0
- package/test/form/fields-optional.test.js +237 -0
- package/test/form/fields-required.test.js +294 -0
- package/test/form/file-upload.test.js +313 -0
- package/test/form/govuk-notify.test.js +449 -0
- package/test/form/journey-basic.test.js +444 -0
- package/test/form/persist-files.test.js +227 -0
- package/test/form/phase-banner.test.js +71 -0
- package/test/form/repeat.test.js +628 -0
- package/test/form/summary-submission-email.test.js +95 -0
- package/test/form/template.test.js +288 -0
- package/test/form/titles.test.js +204 -0
- package/test/helpers/component-helpers.js +74 -0
- package/test/utils/get-cookie.js +42 -0
- package/test/utils/get-form-definitions.js +18 -0
- package/tmp.pdf +1 -0
- package/tsconfig.json +28 -0
- package/webpack.config.js +208 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["Engine","CatboxMemory","CatboxRedis","hapi","inert","Scooter","Wreck","Schmervice","blipp","ProxyAgent","config","requestLogger","requestTracing","buildRedisClient","configureBlankiePlugin","configureCrumbPlugin","configureEnginePlugin","pluginErrorPages","plugin","pluginViews","pluginPulse","pluginRouter","pluginSession","prepareSecureContext","CacheService","proxyAgent","agents","https","http","httpsAllowUnauthorized","serverOptions","debug","request","get","port","router","stripTrailingSlash","routes","validate","options","abortEarly","security","hsts","maxAge","includeSubDomains","preload","xss","noSniff","xframe","cache","name","engine","client","createServer","routeConfig","server","register","pluginEngine","pluginCrumb","pluginBlankie","registerService","ext","h","response","continue","header","path","startsWith","state","ttl","clearInvalid","isHttpOnly","isSecure","encoding"],"sources":["../../src/server/index.ts"],"sourcesContent":["import { Engine as CatboxMemory } from '@hapi/catbox-memory'\nimport { Engine as CatboxRedis } from '@hapi/catbox-redis'\nimport hapi, {\n type Request,\n type ResponseToolkit,\n type ServerOptions\n} from '@hapi/hapi'\nimport inert from '@hapi/inert'\nimport Scooter from '@hapi/scooter'\nimport Wreck from '@hapi/wreck'\nimport Schmervice from '@hapipal/schmervice'\nimport blipp from 'blipp'\nimport { ProxyAgent } from 'proxy-agent'\n\nimport { config } from '~/src/config/index.js'\nimport { requestLogger } from '~/src/server/common/helpers/logging/request-logger.js'\nimport { requestTracing } from '~/src/server/common/helpers/logging/request-tracing.js'\nimport { buildRedisClient } from '~/src/server/common/helpers/redis-client.js'\nimport { configureBlankiePlugin } from '~/src/server/plugins/blankie.js'\nimport { configureCrumbPlugin } from '~/src/server/plugins/crumb.js'\nimport { configureEnginePlugin } from '~/src/server/plugins/engine/index.js'\nimport pluginErrorPages from '~/src/server/plugins/errorPages.js'\nimport { plugin as pluginViews } from '~/src/server/plugins/nunjucks/index.js'\nimport pluginPulse from '~/src/server/plugins/pulse.js'\nimport pluginRouter from '~/src/server/plugins/router.js'\nimport pluginSession from '~/src/server/plugins/session.js'\nimport { prepareSecureContext } from '~/src/server/secure-context.js'\nimport { CacheService } from '~/src/server/services/index.js'\nimport { type RouteConfig } from '~/src/server/types.js'\n\nconst proxyAgent = new ProxyAgent()\n\nWreck.agents = {\n https: proxyAgent,\n http: proxyAgent,\n httpsAllowUnauthorized: proxyAgent\n}\n\nconst serverOptions = (): ServerOptions => {\n const serverOptions: ServerOptions = {\n debug: { request: [`${config.get('isDevelopment')}`] },\n port: config.get('port'),\n router: {\n stripTrailingSlash: true\n },\n routes: {\n validate: {\n options: {\n abortEarly: false\n }\n },\n security: {\n hsts: {\n maxAge: 31536000,\n includeSubDomains: true,\n preload: false\n },\n xss: 'enabled',\n noSniff: true,\n xframe: true\n }\n },\n cache: [\n {\n name: 'session',\n engine: config.get('isTest')\n ? new CatboxMemory()\n : new CatboxRedis({\n client: buildRedisClient()\n })\n }\n ]\n }\n\n return serverOptions\n}\n\nexport async function createServer(routeConfig?: RouteConfig) {\n const server = hapi.server(serverOptions())\n\n await server.register(requestLogger)\n\n if (config.get('isProduction')) {\n prepareSecureContext(server)\n }\n\n const pluginEngine = await configureEnginePlugin(routeConfig)\n const pluginCrumb = configureCrumbPlugin(routeConfig)\n const pluginBlankie = configureBlankiePlugin()\n\n await server.register(pluginSession)\n await server.register(pluginPulse)\n await server.register(inert)\n await server.register(Scooter)\n await server.register(pluginBlankie)\n await server.register(pluginCrumb)\n await server.register(Schmervice)\n\n server.registerService(CacheService)\n\n server.ext('onPreResponse', (request: Request, h: ResponseToolkit) => {\n const { response } = request\n\n if ('isBoom' in response) {\n return h.continue\n }\n\n // Prevent search engine indexing\n response.header('x-robots-tag', 'noindex, nofollow')\n\n // Disable cache to ensure back/foward navigation updates progress\n if (\n !request.path.startsWith('/javascripts/') &&\n !request.path.startsWith('/stylesheets/') &&\n !request.path.startsWith('/assets/')\n ) {\n response.header('cache-control', 'no-store')\n }\n\n return h.continue\n })\n\n await server.register(pluginViews)\n await server.register(pluginEngine)\n await server.register(pluginRouter)\n await server.register(pluginErrorPages)\n await server.register(blipp)\n await server.register(requestTracing)\n\n server.state('cookieConsent', {\n ttl: 365 * 24 * 60 * 60 * 1000, // 1 year in ms\n clearInvalid: true,\n isHttpOnly: false,\n isSecure: config.get('isProduction'),\n path: '/',\n encoding: 'none' // handle this inside the application so we can share frontend/backend cookie modification\n })\n\n return server\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Blankie from 'blankie';
|
|
2
|
+
import { config } from "../../config/index.js";
|
|
3
|
+
const googleAnalyticsOptions = {
|
|
4
|
+
scriptSrc: ['https://*.googletagmanager.com'],
|
|
5
|
+
imgSrc: ['https://*.google-analytics.com', 'https://*.googletagmanager.com'],
|
|
6
|
+
connectSrc: ['https://*.google-analytics.com', 'https://*.analytics.google.com', 'https://*.googletagmanager.com']
|
|
7
|
+
};
|
|
8
|
+
export const configureBlankiePlugin = () => {
|
|
9
|
+
const gaTrackingId = config.get('googleAnalyticsTrackingId');
|
|
10
|
+
const uploaderUrl = config.get('uploaderUrl');
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
Note that unsafe-inline is a fallback for old browsers that don't support nonces. It will be ignored by modern browsers as the nonce is provided.
|
|
14
|
+
*/
|
|
15
|
+
return {
|
|
16
|
+
plugin: Blankie,
|
|
17
|
+
options: {
|
|
18
|
+
defaultSrc: ['self'],
|
|
19
|
+
fontSrc: ['self', 'data:'],
|
|
20
|
+
connectSrc: [['self'], gaTrackingId ? googleAnalyticsOptions.connectSrc : [], uploaderUrl ? [uploaderUrl] : []].flat(),
|
|
21
|
+
scriptSrc: [['self', 'strict-dynamic', 'unsafe-inline'], gaTrackingId ? googleAnalyticsOptions.scriptSrc : []].flat(),
|
|
22
|
+
styleSrc: ['self', 'unsafe-inline'],
|
|
23
|
+
imgSrc: [['self'], gaTrackingId ? googleAnalyticsOptions.imgSrc : []].flat(),
|
|
24
|
+
frameSrc: ['self', 'data:'],
|
|
25
|
+
generateNonces: true
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=blankie.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blankie.js","names":["Blankie","config","googleAnalyticsOptions","scriptSrc","imgSrc","connectSrc","configureBlankiePlugin","gaTrackingId","get","uploaderUrl","plugin","options","defaultSrc","fontSrc","flat","styleSrc","frameSrc","generateNonces"],"sources":["../../../src/server/plugins/blankie.ts"],"sourcesContent":["import { type ServerRegisterPluginObject } from '@hapi/hapi'\nimport Blankie from 'blankie'\n\nimport { config } from '~/src/config/index.js'\n\nconst googleAnalyticsOptions = {\n scriptSrc: ['https://*.googletagmanager.com'],\n imgSrc: ['https://*.google-analytics.com', 'https://*.googletagmanager.com'],\n connectSrc: [\n 'https://*.google-analytics.com',\n 'https://*.analytics.google.com',\n 'https://*.googletagmanager.com'\n ]\n}\n\nexport const configureBlankiePlugin = (): ServerRegisterPluginObject<\n Record<string, boolean | string | string[]>\n> => {\n const gaTrackingId = config.get('googleAnalyticsTrackingId')\n const uploaderUrl = config.get('uploaderUrl')\n\n /*\n Note that unsafe-inline is a fallback for old browsers that don't support nonces. It will be ignored by modern browsers as the nonce is provided.\n */\n return {\n plugin: Blankie,\n options: {\n defaultSrc: ['self'],\n fontSrc: ['self', 'data:'],\n connectSrc: [\n ['self'],\n gaTrackingId ? googleAnalyticsOptions.connectSrc : [],\n uploaderUrl ? [uploaderUrl] : []\n ].flat(),\n scriptSrc: [\n ['self', 'strict-dynamic', 'unsafe-inline'],\n gaTrackingId ? googleAnalyticsOptions.scriptSrc : []\n ].flat(),\n styleSrc: ['self', 'unsafe-inline'],\n imgSrc: [\n ['self'],\n gaTrackingId ? googleAnalyticsOptions.imgSrc : []\n ].flat(),\n frameSrc: ['self', 'data:'],\n generateNonces: true\n }\n }\n}\n"],"mappings":"AACA,OAAOA,OAAO,MAAM,SAAS;AAE7B,SAASC,MAAM;AAEf,MAAMC,sBAAsB,GAAG;EAC7BC,SAAS,EAAE,CAAC,gCAAgC,CAAC;EAC7CC,MAAM,EAAE,CAAC,gCAAgC,EAAE,gCAAgC,CAAC;EAC5EC,UAAU,EAAE,CACV,gCAAgC,EAChC,gCAAgC,EAChC,gCAAgC;AAEpC,CAAC;AAED,OAAO,MAAMC,sBAAsB,GAAGA,CAAA,KAEjC;EACH,MAAMC,YAAY,GAAGN,MAAM,CAACO,GAAG,CAAC,2BAA2B,CAAC;EAC5D,MAAMC,WAAW,GAAGR,MAAM,CAACO,GAAG,CAAC,aAAa,CAAC;;EAE7C;AACF;AACA;EACE,OAAO;IACLE,MAAM,EAAEV,OAAO;IACfW,OAAO,EAAE;MACPC,UAAU,EAAE,CAAC,MAAM,CAAC;MACpBC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;MAC1BR,UAAU,EAAE,CACV,CAAC,MAAM,CAAC,EACRE,YAAY,GAAGL,sBAAsB,CAACG,UAAU,GAAG,EAAE,EACrDI,WAAW,GAAG,CAACA,WAAW,CAAC,GAAG,EAAE,CACjC,CAACK,IAAI,CAAC,CAAC;MACRX,SAAS,EAAE,CACT,CAAC,MAAM,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAC3CI,YAAY,GAAGL,sBAAsB,CAACC,SAAS,GAAG,EAAE,CACrD,CAACW,IAAI,CAAC,CAAC;MACRC,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC;MACnCX,MAAM,EAAE,CACN,CAAC,MAAM,CAAC,EACRG,YAAY,GAAGL,sBAAsB,CAACE,MAAM,GAAG,EAAE,CAClD,CAACU,IAAI,CAAC,CAAC;MACRE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;MAC3BC,cAAc,EAAE;IAClB;EACF,CAAC;AACH,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import crumb from '@hapi/crumb';
|
|
2
|
+
import { config } from "../../config/index.js";
|
|
3
|
+
export const configureCrumbPlugin = routeConfig => {
|
|
4
|
+
return {
|
|
5
|
+
plugin: crumb,
|
|
6
|
+
options: {
|
|
7
|
+
logUnauthorized: true,
|
|
8
|
+
enforce: routeConfig?.enforceCsrf ?? config.get('enforceCsrf'),
|
|
9
|
+
cookieOptions: {
|
|
10
|
+
isSecure: config.get('isProduction')
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=crumb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crumb.js","names":["crumb","config","configureCrumbPlugin","routeConfig","plugin","options","logUnauthorized","enforce","enforceCsrf","get","cookieOptions","isSecure"],"sources":["../../../src/server/plugins/crumb.ts"],"sourcesContent":["import crumb, { type RegisterOptions } from '@hapi/crumb'\nimport { type ServerRegisterPluginObject } from '@hapi/hapi'\n\nimport { config } from '~/src/config/index.js'\nimport { type RouteConfig } from '~/src/server/types.js'\n\nexport const configureCrumbPlugin = (\n routeConfig?: RouteConfig\n): ServerRegisterPluginObject<RegisterOptions> => {\n return {\n plugin: crumb,\n options: {\n logUnauthorized: true,\n enforce: routeConfig?.enforceCsrf ?? config.get('enforceCsrf'),\n cookieOptions: {\n isSecure: config.get('isProduction')\n }\n }\n }\n}\n"],"mappings":"AAAA,OAAOA,KAAK,MAAgC,aAAa;AAGzD,SAASC,MAAM;AAGf,OAAO,MAAMC,oBAAoB,GAC/BC,WAAyB,IACuB;EAChD,OAAO;IACLC,MAAM,EAAEJ,KAAK;IACbK,OAAO,EAAE;MACPC,eAAe,EAAE,IAAI;MACrBC,OAAO,EAAEJ,WAAW,EAAEK,WAAW,IAAIP,MAAM,CAACQ,GAAG,CAAC,aAAa,CAAC;MAC9DC,aAAa,EAAE;QACbC,QAAQ,EAAEV,MAAM,CAACQ,GAAG,CAAC,cAAc;MACrC;IACF;EACF,CAAC;AACH,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# forms-engine
|
|
2
|
+
|
|
3
|
+
Form hapi-plugin
|
|
4
|
+
|
|
5
|
+
...
|
|
6
|
+
|
|
7
|
+
## Templates
|
|
8
|
+
|
|
9
|
+
The following elements support [LiquidJS templates](https://liquidjs.com/):
|
|
10
|
+
|
|
11
|
+
- Page **title**
|
|
12
|
+
- Form component **titles**
|
|
13
|
+
- Support for fieldset legend text or label text
|
|
14
|
+
- This includes when the title is used in **error messages**
|
|
15
|
+
- Html (guidance) component **content**
|
|
16
|
+
- Summary component **row** key title (check answers and repeater summary)
|
|
17
|
+
|
|
18
|
+
### Template data
|
|
19
|
+
|
|
20
|
+
The data the templates are evaluated against is the raw answers the user has provided up to the page they're currently on.
|
|
21
|
+
For example, given a YesNoField component called `TKsWbP`, the template `{{ TKsWbP }}` would render "true" or "false" depending on how the user answered the question.
|
|
22
|
+
|
|
23
|
+
The current FormContext is also available as `context` in the templates. This allows access to the full data including the path the user has taken in their journey and any miscellaneous data returned from `Page event`s in `context.data`.
|
|
24
|
+
|
|
25
|
+
### Liquid Filters
|
|
26
|
+
|
|
27
|
+
There are a number of `LiquidJS` filters available to you from within the templates:
|
|
28
|
+
|
|
29
|
+
- `page` - returns the page definition for the given path
|
|
30
|
+
- `field` - returns the component definition for the given name
|
|
31
|
+
- `href` - returns the page href for the given page path
|
|
32
|
+
- `answer` - returns the user's answer for a given component
|
|
33
|
+
- `evaluate` - evaluates and returns a Liquid template using the current context
|
|
34
|
+
|
|
35
|
+
### Examples
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
"pages": [
|
|
39
|
+
{
|
|
40
|
+
"title": "What's your name?",
|
|
41
|
+
"path": "/full-name",
|
|
42
|
+
"components": [
|
|
43
|
+
{
|
|
44
|
+
"name": "WmHfSb",
|
|
45
|
+
"title": "What's your full name?",
|
|
46
|
+
"type": "TextField"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
// This example shows how a component can use an answer to a previous question (What's your full name) in it's title
|
|
51
|
+
{
|
|
52
|
+
"title": "Are you in England?",
|
|
53
|
+
"path": "/are-you-in-england",
|
|
54
|
+
"components": [
|
|
55
|
+
{
|
|
56
|
+
"name": "TKsWbP",
|
|
57
|
+
"title": "Are you in England, {{ WmHfSb }}?",
|
|
58
|
+
"type": "YesNoField"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
// This example shows how a Html (guidance) component can use the available filters to get the form definition and user answers and display them
|
|
63
|
+
{
|
|
64
|
+
"title": "Template example for {{ WmHfSb }}?",
|
|
65
|
+
"path": "/example",
|
|
66
|
+
"components": [
|
|
67
|
+
{
|
|
68
|
+
"title": "Html",
|
|
69
|
+
"type": "Html",
|
|
70
|
+
"content": "<p class=\"govuk-body\">
|
|
71
|
+
// Use Liquid's `assign` to create a variable that holds reference to the \"/are-you-in-england\" page
|
|
72
|
+
{%- assign inEngland = \"/are-you-in-england\" | page -%}
|
|
73
|
+
|
|
74
|
+
// Use the reference to `evaluate` the title
|
|
75
|
+
{{ inEngland.title | evaluate }}<br>
|
|
76
|
+
|
|
77
|
+
// Use the href filter to display the full page path
|
|
78
|
+
{{ \"/are-you-in-england\" | href }}<br>
|
|
79
|
+
|
|
80
|
+
// Use the `answer` filter to render the user provided answer to a question
|
|
81
|
+
{{ 'TKsWbP' | answer }}
|
|
82
|
+
</p>\n"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SelectField } from "./SelectField.js";
|
|
2
|
+
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
3
|
+
export class AutocompleteField extends SelectField {
|
|
4
|
+
constructor(def, props) {
|
|
5
|
+
super(def, props);
|
|
6
|
+
const {
|
|
7
|
+
options
|
|
8
|
+
} = def;
|
|
9
|
+
let {
|
|
10
|
+
formSchema
|
|
11
|
+
} = this;
|
|
12
|
+
if (options.required !== false) {
|
|
13
|
+
const messages = options.customValidationMessages;
|
|
14
|
+
formSchema = formSchema.messages({
|
|
15
|
+
'any.only': messages?.['any.only'] ?? messageTemplate.required,
|
|
16
|
+
'any.required': messages?.['any.required'] ?? messageTemplate.required
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.formSchema = formSchema;
|
|
21
|
+
}
|
|
22
|
+
getViewModel(payload, errors) {
|
|
23
|
+
const viewModel = super.getViewModel(payload, errors);
|
|
24
|
+
let {
|
|
25
|
+
formGroup
|
|
26
|
+
} = viewModel;
|
|
27
|
+
formGroup ??= {};
|
|
28
|
+
formGroup.attributes = {
|
|
29
|
+
'data-module': 'govuk-accessible-autocomplete'
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
...viewModel,
|
|
33
|
+
formGroup
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=AutocompleteField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteField.js","names":["SelectField","messageTemplate","AutocompleteField","constructor","def","props","options","formSchema","required","messages","customValidationMessages","getViewModel","payload","errors","viewModel","formGroup","attributes"],"sources":["../../../../../src/server/plugins/engine/components/AutocompleteField.ts"],"sourcesContent":["import { type AutocompleteFieldComponent } from '@defra/forms-model'\n\nimport { SelectField } from '~/src/server/plugins/engine/components/SelectField.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nexport class AutocompleteField extends SelectField {\n declare options: AutocompleteFieldComponent['options']\n\n constructor(\n def: AutocompleteFieldComponent,\n props: ConstructorParameters<typeof SelectField>[1]\n ) {\n super(def, props)\n\n const { options } = def\n let { formSchema } = this\n\n if (options.required !== false) {\n const messages = options.customValidationMessages\n\n formSchema = formSchema.messages({\n 'any.only': messages?.['any.only'] ?? messageTemplate.required,\n 'any.required': messages?.['any.required'] ?? messageTemplate.required\n })\n }\n\n this.options = options\n this.formSchema = formSchema\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n let { formGroup } = viewModel\n\n formGroup ??= {}\n formGroup.attributes = {\n 'data-module': 'govuk-accessible-autocomplete'\n }\n\n return {\n ...viewModel,\n formGroup\n }\n }\n}\n"],"mappings":"AAEA,SAASA,WAAW;AACpB,SAASC,eAAe;AAMxB,OAAO,MAAMC,iBAAiB,SAASF,WAAW,CAAC;EAGjDG,WAAWA,CACTC,GAA+B,EAC/BC,KAAmD,EACnD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEC;IAAQ,CAAC,GAAGF,GAAG;IACvB,IAAI;MAAEG;IAAW,CAAC,GAAG,IAAI;IAEzB,IAAID,OAAO,CAACE,QAAQ,KAAK,KAAK,EAAE;MAC9B,MAAMC,QAAQ,GAAGH,OAAO,CAACI,wBAAwB;MAEjDH,UAAU,GAAGA,UAAU,CAACE,QAAQ,CAAC;QAC/B,UAAU,EAAEA,QAAQ,GAAG,UAAU,CAAC,IAAIR,eAAe,CAACO,QAAQ;QAC9D,cAAc,EAAEC,QAAQ,GAAG,cAAc,CAAC,IAAIR,eAAe,CAACO;MAChE,CAAC,CAAC;IACJ;IAEA,IAAI,CAACF,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACC,UAAU,GAAGA,UAAU;EAC9B;EAEAI,YAAYA,CAACC,OAAoB,EAAEC,MAA8B,EAAE;IACjE,MAAMC,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,EAAEC,MAAM,CAAC;IACrD,IAAI;MAAEE;IAAU,CAAC,GAAGD,SAAS;IAE7BC,SAAS,KAAK,CAAC,CAAC;IAChBA,SAAS,CAACC,UAAU,GAAG;MACrB,aAAa,EAAE;IACjB,CAAC;IAED,OAAO;MACL,GAAGF,SAAS;MACZC;IACF,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
import { isFormValue } from "./FormComponent.js";
|
|
3
|
+
import { SelectionControlField } from "./SelectionControlField.js";
|
|
4
|
+
export class CheckboxesField extends SelectionControlField {
|
|
5
|
+
constructor(def, props) {
|
|
6
|
+
super(def, props);
|
|
7
|
+
const {
|
|
8
|
+
listType: type
|
|
9
|
+
} = this;
|
|
10
|
+
const {
|
|
11
|
+
options,
|
|
12
|
+
title
|
|
13
|
+
} = def;
|
|
14
|
+
let formSchema = type === 'string' ? joi.array() : joi.array();
|
|
15
|
+
const itemsSchema = joi[type]().valid(...this.values).label(title);
|
|
16
|
+
formSchema = formSchema.items(itemsSchema).single().label(title).required();
|
|
17
|
+
if (options.required === false) {
|
|
18
|
+
formSchema = formSchema.optional();
|
|
19
|
+
}
|
|
20
|
+
this.formSchema = formSchema.default([]);
|
|
21
|
+
this.stateSchema = formSchema.default(null).allow(null);
|
|
22
|
+
this.options = options;
|
|
23
|
+
}
|
|
24
|
+
getFormValueFromState(state) {
|
|
25
|
+
const {
|
|
26
|
+
items,
|
|
27
|
+
name
|
|
28
|
+
} = this;
|
|
29
|
+
|
|
30
|
+
// State checkbox values
|
|
31
|
+
const values = this.getFormValue(state[name]) ?? [];
|
|
32
|
+
|
|
33
|
+
// Map (or discard) state values to item values
|
|
34
|
+
const selected = items.filter(item => values.includes(item.value)).map(item => item.value);
|
|
35
|
+
return selected.length ? selected : undefined;
|
|
36
|
+
}
|
|
37
|
+
getFormValue(value) {
|
|
38
|
+
return this.isValue(value) ? value : undefined;
|
|
39
|
+
}
|
|
40
|
+
getDisplayStringFromState(state) {
|
|
41
|
+
const {
|
|
42
|
+
items
|
|
43
|
+
} = this;
|
|
44
|
+
|
|
45
|
+
// Selected checkbox values
|
|
46
|
+
const selected = this.getFormValueFromState(state) ?? [];
|
|
47
|
+
|
|
48
|
+
// Map selected values to text
|
|
49
|
+
return items.filter(item => selected.includes(item.value)).map(item => item.text).join(', ');
|
|
50
|
+
}
|
|
51
|
+
getContextValueFromState(state) {
|
|
52
|
+
const values = this.getFormValueFromState(state);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* For evaluation context purposes, optional {@link CheckboxesField}
|
|
56
|
+
* with an undefined value (i.e. nothing selected) should default to [].
|
|
57
|
+
* This way conditions are not evaluated against `undefined` which throws errors.
|
|
58
|
+
* Currently these errors are caught and the evaluation returns default `false`.
|
|
59
|
+
* @see {@link QuestionPageController.getNextPath} for `undefined` return value
|
|
60
|
+
* @see {@link FormModel.makeCondition} for try/catch block with default `false`
|
|
61
|
+
* For negative conditions this is a problem because E.g.
|
|
62
|
+
* The condition: 'selectedchecks' does not contain 'someval'
|
|
63
|
+
* should return true IF 'selectedchecks' is undefined, not throw and return false.
|
|
64
|
+
*/
|
|
65
|
+
return values ?? [];
|
|
66
|
+
}
|
|
67
|
+
isValue(value) {
|
|
68
|
+
if (!Array.isArray(value)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Skip checks when empty
|
|
73
|
+
if (!value.length) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return value.every(isFormValue);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=CheckboxesField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckboxesField.js","names":["joi","isFormValue","SelectionControlField","CheckboxesField","constructor","def","props","listType","type","options","title","formSchema","array","itemsSchema","valid","values","label","items","single","required","optional","default","stateSchema","allow","getFormValueFromState","state","name","getFormValue","selected","filter","item","includes","value","map","length","undefined","isValue","getDisplayStringFromState","text","join","getContextValueFromState","Array","isArray","every"],"sources":["../../../../../src/server/plugins/engine/components/CheckboxesField.ts"],"sourcesContent":["import { type CheckboxesFieldComponent, type Item } from '@defra/forms-model'\nimport joi, { type ArraySchema } from 'joi'\n\nimport { isFormValue } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { SelectionControlField } from '~/src/server/plugins/engine/components/SelectionControlField.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class CheckboxesField extends SelectionControlField {\n declare options: CheckboxesFieldComponent['options']\n declare formSchema: ArraySchema<string> | ArraySchema<number>\n declare stateSchema: ArraySchema<string> | ArraySchema<number>\n\n constructor(\n def: CheckboxesFieldComponent,\n props: ConstructorParameters<typeof SelectionControlField>[1]\n ) {\n super(def, props)\n\n const { listType: type } = this\n const { options, title } = def\n\n let formSchema =\n type === 'string' ? joi.array<string>() : joi.array<number>()\n\n const itemsSchema = joi[type]()\n .valid(...this.values)\n .label(title)\n\n formSchema = formSchema.items(itemsSchema).single().label(title).required()\n\n if (options.required === false) {\n formSchema = formSchema.optional()\n }\n\n this.formSchema = formSchema.default([])\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = options\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { items, name } = this\n\n // State checkbox values\n const values = this.getFormValue(state[name]) ?? []\n\n // Map (or discard) state values to item values\n const selected = items\n .filter((item) => values.includes(item.value))\n .map((item) => item.value)\n\n return selected.length ? selected : undefined\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const { items } = this\n\n // Selected checkbox values\n const selected = this.getFormValueFromState(state) ?? []\n\n // Map selected values to text\n return items\n .filter((item) => selected.includes(item.value))\n .map((item) => item.text)\n .join(', ')\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const values = this.getFormValueFromState(state)\n\n /**\n * For evaluation context purposes, optional {@link CheckboxesField}\n * with an undefined value (i.e. nothing selected) should default to [].\n * This way conditions are not evaluated against `undefined` which throws errors.\n * Currently these errors are caught and the evaluation returns default `false`.\n * @see {@link QuestionPageController.getNextPath} for `undefined` return value\n * @see {@link FormModel.makeCondition} for try/catch block with default `false`\n * For negative conditions this is a problem because E.g.\n * The condition: 'selectedchecks' does not contain 'someval'\n * should return true IF 'selectedchecks' is undefined, not throw and return false.\n */\n return values ?? []\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { isConditionalType } from '@defra/forms-model';
|
|
2
|
+
import joi from 'joi';
|
|
3
|
+
export class ComponentBase {
|
|
4
|
+
page;
|
|
5
|
+
parent;
|
|
6
|
+
collection;
|
|
7
|
+
type;
|
|
8
|
+
name;
|
|
9
|
+
title;
|
|
10
|
+
schema;
|
|
11
|
+
options;
|
|
12
|
+
isFormComponent = false;
|
|
13
|
+
model;
|
|
14
|
+
|
|
15
|
+
/** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */
|
|
16
|
+
formSchema = joi.string();
|
|
17
|
+
stateSchema = joi.string();
|
|
18
|
+
constructor(def, props) {
|
|
19
|
+
this.type = def.type;
|
|
20
|
+
this.name = def.name;
|
|
21
|
+
this.title = def.title;
|
|
22
|
+
if ('schema' in def) {
|
|
23
|
+
this.schema = def.schema;
|
|
24
|
+
}
|
|
25
|
+
if ('options' in def) {
|
|
26
|
+
this.options = def.options;
|
|
27
|
+
}
|
|
28
|
+
this.page = props.page;
|
|
29
|
+
this.parent = props.parent;
|
|
30
|
+
this.model = props.model;
|
|
31
|
+
}
|
|
32
|
+
get viewModel() {
|
|
33
|
+
const {
|
|
34
|
+
options,
|
|
35
|
+
type
|
|
36
|
+
} = this;
|
|
37
|
+
const viewModel = {
|
|
38
|
+
attributes: {}
|
|
39
|
+
};
|
|
40
|
+
if (!options) {
|
|
41
|
+
return viewModel;
|
|
42
|
+
}
|
|
43
|
+
if ('autocomplete' in options) {
|
|
44
|
+
viewModel.attributes.autocomplete = options.autocomplete;
|
|
45
|
+
}
|
|
46
|
+
if ('classes' in options) {
|
|
47
|
+
viewModel.classes = options.classes;
|
|
48
|
+
}
|
|
49
|
+
if ('condition' in options && isConditionalType(type)) {
|
|
50
|
+
viewModel.condition = options.condition;
|
|
51
|
+
}
|
|
52
|
+
return viewModel;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=ComponentBase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentBase.js","names":["isConditionalType","joi","ComponentBase","page","parent","collection","type","name","title","schema","options","isFormComponent","model","formSchema","string","stateSchema","constructor","def","props","viewModel","attributes","autocomplete","classes","condition"],"sources":["../../../../../src/server/plugins/engine/components/ComponentBase.ts"],"sourcesContent":["import { isConditionalType, type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type DateSchema,\n type NumberSchema,\n type ObjectSchema,\n type StringSchema\n} from 'joi'\n\nimport { type ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers.js'\nimport { type ViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\n\nexport class ComponentBase {\n page?: PageControllerClass\n parent: Component | undefined\n collection: ComponentCollection | undefined\n\n type: ComponentDef['type']\n name: ComponentDef['name']\n title: ComponentDef['title']\n schema?: Extract<ComponentDef, { schema: object }>['schema']\n options?: Extract<ComponentDef, { options: object }>['options']\n\n isFormComponent = false\n model: FormModel\n\n /** joi schemas based on a component defined in the form JSON. This validates a user's answer and is generated from {@link ComponentDef} */\n formSchema: ComponentSchema = joi.string()\n stateSchema: ComponentSchema = joi.string()\n\n constructor(\n def: ComponentDef,\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n }\n ) {\n this.type = def.type\n this.name = def.name\n this.title = def.title\n\n if ('schema' in def) {\n this.schema = def.schema\n }\n\n if ('options' in def) {\n this.options = def.options\n }\n\n this.page = props.page\n this.parent = props.parent\n this.model = props.model\n }\n\n get viewModel() {\n const { options, type } = this\n\n const viewModel: ViewModel = {\n attributes: {}\n }\n\n if (!options) {\n return viewModel\n }\n\n if ('autocomplete' in options) {\n viewModel.attributes.autocomplete = options.autocomplete\n }\n\n if ('classes' in options) {\n viewModel.classes = options.classes\n }\n\n if ('condition' in options && isConditionalType(type)) {\n viewModel.condition = options.condition\n }\n\n return viewModel\n }\n}\n\nexport type ComponentSchema =\n | ArraySchema<string>\n | ArraySchema<number>\n | ArraySchema<boolean>\n | ArraySchema<object>\n | BooleanSchema<string>\n | DateSchema\n | NumberSchema<string>\n | NumberSchema\n | ObjectSchema\n | StringSchema\n"],"mappings":"AAAA,SAASA,iBAAiB,QAA2B,oBAAoB;AACzE,OAAOC,GAAG,MAOH,KAAK;AAQZ,OAAO,MAAMC,aAAa,CAAC;EACzBC,IAAI;EACJC,MAAM;EACNC,UAAU;EAEVC,IAAI;EACJC,IAAI;EACJC,KAAK;EACLC,MAAM;EACNC,OAAO;EAEPC,eAAe,GAAG,KAAK;EACvBC,KAAK;;EAEL;EACAC,UAAU,GAAoBZ,GAAG,CAACa,MAAM,CAAC,CAAC;EAC1CC,WAAW,GAAoBd,GAAG,CAACa,MAAM,CAAC,CAAC;EAE3CE,WAAWA,CACTC,GAAiB,EACjBC,KAIC,EACD;IACA,IAAI,CAACZ,IAAI,GAAGW,GAAG,CAACX,IAAI;IACpB,IAAI,CAACC,IAAI,GAAGU,GAAG,CAACV,IAAI;IACpB,IAAI,CAACC,KAAK,GAAGS,GAAG,CAACT,KAAK;IAEtB,IAAI,QAAQ,IAAIS,GAAG,EAAE;MACnB,IAAI,CAACR,MAAM,GAAGQ,GAAG,CAACR,MAAM;IAC1B;IAEA,IAAI,SAAS,IAAIQ,GAAG,EAAE;MACpB,IAAI,CAACP,OAAO,GAAGO,GAAG,CAACP,OAAO;IAC5B;IAEA,IAAI,CAACP,IAAI,GAAGe,KAAK,CAACf,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGc,KAAK,CAACd,MAAM;IAC1B,IAAI,CAACQ,KAAK,GAAGM,KAAK,CAACN,KAAK;EAC1B;EAEA,IAAIO,SAASA,CAAA,EAAG;IACd,MAAM;MAAET,OAAO;MAAEJ;IAAK,CAAC,GAAG,IAAI;IAE9B,MAAMa,SAAoB,GAAG;MAC3BC,UAAU,EAAE,CAAC;IACf,CAAC;IAED,IAAI,CAACV,OAAO,EAAE;MACZ,OAAOS,SAAS;IAClB;IAEA,IAAI,cAAc,IAAIT,OAAO,EAAE;MAC7BS,SAAS,CAACC,UAAU,CAACC,YAAY,GAAGX,OAAO,CAACW,YAAY;IAC1D;IAEA,IAAI,SAAS,IAAIX,OAAO,EAAE;MACxBS,SAAS,CAACG,OAAO,GAAGZ,OAAO,CAACY,OAAO;IACrC;IAEA,IAAI,WAAW,IAAIZ,OAAO,IAAIV,iBAAiB,CAACM,IAAI,CAAC,EAAE;MACrDa,SAAS,CAACI,SAAS,GAAGb,OAAO,CAACa,SAAS;IACzC;IAEA,OAAOJ,SAAS;EAClB;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
import { FormComponent, isFormState, isFormValue } from "./FormComponent.js";
|
|
3
|
+
import { createComponent } from "./helpers.js";
|
|
4
|
+
import { getErrors } from "../helpers.js";
|
|
5
|
+
import { validationOptions as opts } from "../pageControllers/validationOptions.js";
|
|
6
|
+
export class ComponentCollection {
|
|
7
|
+
page;
|
|
8
|
+
parent;
|
|
9
|
+
components;
|
|
10
|
+
fields;
|
|
11
|
+
guidance;
|
|
12
|
+
formSchema;
|
|
13
|
+
stateSchema;
|
|
14
|
+
constructor(defs, props, schema) {
|
|
15
|
+
const components = defs.map(def => createComponent(def, props));
|
|
16
|
+
const fields = components.filter(component => component.isFormComponent);
|
|
17
|
+
const guidance = components.filter(component => !component.isFormComponent);
|
|
18
|
+
let formSchema = joi.object().required();
|
|
19
|
+
let stateSchema = joi.object().required();
|
|
20
|
+
|
|
21
|
+
// Add each field or concat collection
|
|
22
|
+
for (const field of fields) {
|
|
23
|
+
const {
|
|
24
|
+
collection,
|
|
25
|
+
name
|
|
26
|
+
} = field;
|
|
27
|
+
formSchema = collection ? formSchema.concat(collection.formSchema) : formSchema.keys({
|
|
28
|
+
[name]: field.formSchema
|
|
29
|
+
});
|
|
30
|
+
stateSchema = collection ? stateSchema.concat(collection.stateSchema) : stateSchema.keys({
|
|
31
|
+
[name]: field.stateSchema
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Add parent field title to collection field errors
|
|
36
|
+
formSchema = formSchema.error(errors => {
|
|
37
|
+
return errors.flatMap(error => {
|
|
38
|
+
if (!isErrorContext(error.local) || error.local.title) {
|
|
39
|
+
return error;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Use field key or first missing child field
|
|
43
|
+
let {
|
|
44
|
+
missing,
|
|
45
|
+
key = missing?.[0]
|
|
46
|
+
} = error.local;
|
|
47
|
+
|
|
48
|
+
// But avoid numeric key used by array payloads
|
|
49
|
+
if (typeof key === 'number') {
|
|
50
|
+
key = error.path[0];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Find the parent field
|
|
54
|
+
const parent = fields.find(item => item.name === key?.split('__').shift());
|
|
55
|
+
|
|
56
|
+
// Find the child field
|
|
57
|
+
const child = (parent?.collection?.fields ?? fields).find(item => item.name === key);
|
|
58
|
+
|
|
59
|
+
// Update error with child label
|
|
60
|
+
if (child && (!error.local.label || error.local.label === 'value')) {
|
|
61
|
+
error.local.label = child.title;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Fix error summary links for missing fields
|
|
65
|
+
if (missing?.length) {
|
|
66
|
+
error.path = missing;
|
|
67
|
+
error.local.key = missing[0];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Update error with parent title
|
|
71
|
+
error.local.title ??= parent?.title;
|
|
72
|
+
return error;
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
if (schema?.peers) {
|
|
76
|
+
formSchema = formSchema.and(...schema.peers, {
|
|
77
|
+
isPresent: isFormValue
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (schema?.custom) {
|
|
81
|
+
formSchema = formSchema.custom(schema.custom);
|
|
82
|
+
}
|
|
83
|
+
this.page = props.page;
|
|
84
|
+
this.parent = props.parent;
|
|
85
|
+
this.components = components;
|
|
86
|
+
this.fields = fields;
|
|
87
|
+
this.guidance = guidance;
|
|
88
|
+
this.formSchema = formSchema;
|
|
89
|
+
this.stateSchema = stateSchema;
|
|
90
|
+
}
|
|
91
|
+
get keys() {
|
|
92
|
+
return this.fields.flatMap(field => {
|
|
93
|
+
const {
|
|
94
|
+
name,
|
|
95
|
+
collection
|
|
96
|
+
} = field;
|
|
97
|
+
if (collection) {
|
|
98
|
+
const {
|
|
99
|
+
fields
|
|
100
|
+
} = collection;
|
|
101
|
+
return [name, ...fields.map(({
|
|
102
|
+
name
|
|
103
|
+
}) => name)];
|
|
104
|
+
}
|
|
105
|
+
return [name];
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
getFormDataFromState(state) {
|
|
109
|
+
const payload = {};
|
|
110
|
+
this.fields.forEach(component => {
|
|
111
|
+
Object.assign(payload, component.getFormDataFromState(state));
|
|
112
|
+
});
|
|
113
|
+
return payload;
|
|
114
|
+
}
|
|
115
|
+
getFormValueFromState(state) {
|
|
116
|
+
const payload = {};
|
|
117
|
+
|
|
118
|
+
// Remove name prefix for formatted value
|
|
119
|
+
for (const [name, value] of Object.entries(this.getFormDataFromState(state))) {
|
|
120
|
+
const key = name.split('__').pop();
|
|
121
|
+
if (!key) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
payload[key] = value;
|
|
125
|
+
}
|
|
126
|
+
return payload;
|
|
127
|
+
}
|
|
128
|
+
getStateFromValidForm(payload) {
|
|
129
|
+
const state = {};
|
|
130
|
+
this.fields.forEach(component => {
|
|
131
|
+
Object.assign(state, component.getStateFromValidForm(payload));
|
|
132
|
+
});
|
|
133
|
+
return state;
|
|
134
|
+
}
|
|
135
|
+
getContextValueFromState(state) {
|
|
136
|
+
const context = {};
|
|
137
|
+
for (const component of this.fields) {
|
|
138
|
+
context[component.name] = component.getContextValueFromState(state);
|
|
139
|
+
}
|
|
140
|
+
return context;
|
|
141
|
+
}
|
|
142
|
+
getErrors(errors) {
|
|
143
|
+
const {
|
|
144
|
+
fields
|
|
145
|
+
} = this;
|
|
146
|
+
const list = [];
|
|
147
|
+
|
|
148
|
+
// Add only one error per field
|
|
149
|
+
for (const field of fields) {
|
|
150
|
+
const error = field.getError(errors);
|
|
151
|
+
if (error) {
|
|
152
|
+
list.push(error);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!list.length) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
return list;
|
|
159
|
+
}
|
|
160
|
+
getViewModel(payload, errors, query = {}) {
|
|
161
|
+
const {
|
|
162
|
+
components
|
|
163
|
+
} = this;
|
|
164
|
+
const result = components.map(component => {
|
|
165
|
+
const {
|
|
166
|
+
isFormComponent,
|
|
167
|
+
type
|
|
168
|
+
} = component;
|
|
169
|
+
const model = component instanceof FormComponent ? component.getViewModel(payload, errors, query) : component.getViewModel();
|
|
170
|
+
return {
|
|
171
|
+
type,
|
|
172
|
+
isFormComponent,
|
|
173
|
+
model
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Validate form payload
|
|
181
|
+
*/
|
|
182
|
+
validate(value = {}) {
|
|
183
|
+
const result = this.formSchema.validate(value, opts);
|
|
184
|
+
const details = result.error?.details;
|
|
185
|
+
return {
|
|
186
|
+
value: result.value ?? {},
|
|
187
|
+
errors: this.page?.getErrors(details) ?? getErrors(details)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Check for field local state
|
|
194
|
+
*/
|
|
195
|
+
export function isErrorContext(value) {
|
|
196
|
+
return isFormState(value) && typeof value.label === 'string';
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=ComponentCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentCollection.js","names":["joi","FormComponent","isFormState","isFormValue","createComponent","getErrors","validationOptions","opts","ComponentCollection","page","parent","components","fields","guidance","formSchema","stateSchema","constructor","defs","props","schema","map","def","filter","component","isFormComponent","object","required","field","collection","name","concat","keys","error","errors","flatMap","isErrorContext","local","title","missing","key","path","find","item","split","shift","child","label","length","peers","and","isPresent","custom","getFormDataFromState","state","payload","forEach","Object","assign","getFormValueFromState","value","entries","pop","getStateFromValidForm","getContextValueFromState","context","list","getError","push","getViewModel","query","result","type","model","validate","details"],"sources":["../../../../../src/server/plugins/engine/components/ComponentCollection.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, {\n type CustomValidator,\n type ErrorReportCollection,\n type ObjectSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormState,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n createComponent,\n type Component,\n type Field,\n type Guidance\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type ComponentViewModel } from '~/src/server/plugins/engine/components/types.js'\nimport { getErrors } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValidationResult\n} from '~/src/server/plugins/engine/types.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\n\nexport class ComponentCollection {\n page?: PageControllerClass\n parent?: Component\n\n components: Component[]\n fields: Field[]\n guidance: Guidance[]\n\n formSchema: ObjectSchema<FormPayload>\n stateSchema: ObjectSchema<FormSubmissionState>\n\n constructor(\n defs: ComponentDef[],\n props: {\n page?: PageControllerClass\n parent?: Component\n model: FormModel\n },\n schema?: {\n /**\n * Defines an all-or-nothing relationship between keys where if one\n * of the peers is present, all of them are required as well\n */\n peers?: string[]\n\n /**\n * Defines a custom validation rule for the object schema\n */\n custom?: CustomValidator\n }\n ) {\n const components = defs.map((def) => createComponent(def, props))\n\n const fields = components.filter(\n (component): component is Field => component.isFormComponent\n )\n\n const guidance = components.filter(\n (component): component is Guidance => !component.isFormComponent\n )\n\n let formSchema = joi.object<FormPayload>().required()\n let stateSchema = joi.object<FormSubmissionState>().required()\n\n // Add each field or concat collection\n for (const field of fields) {\n const { collection, name } = field\n\n formSchema = collection\n ? formSchema.concat(collection.formSchema)\n : formSchema.keys({ [name]: field.formSchema })\n\n stateSchema = collection\n ? stateSchema.concat(collection.stateSchema)\n : stateSchema.keys({ [name]: field.stateSchema })\n }\n\n // Add parent field title to collection field errors\n formSchema = formSchema.error((errors) => {\n return errors.flatMap((error) => {\n if (!isErrorContext(error.local) || error.local.title) {\n return error\n }\n\n // Use field key or first missing child field\n let { missing, key = missing?.[0] } = error.local\n\n // But avoid numeric key used by array payloads\n if (typeof key === 'number') {\n key = error.path[0]\n }\n\n // Find the parent field\n const parent = fields.find(\n (item) => item.name === key?.split('__').shift()\n )\n\n // Find the child field\n const child = (parent?.collection?.fields ?? fields).find(\n (item) => item.name === key\n )\n\n // Update error with child label\n if (child && (!error.local.label || error.local.label === 'value')) {\n error.local.label = child.title\n }\n\n // Fix error summary links for missing fields\n if (missing?.length) {\n error.path = missing\n error.local.key = missing[0]\n }\n\n // Update error with parent title\n error.local.title ??= parent?.title\n\n return error\n })\n })\n\n if (schema?.peers) {\n formSchema = formSchema.and(...schema.peers, {\n isPresent: isFormValue\n })\n }\n\n if (schema?.custom) {\n formSchema = formSchema.custom(schema.custom)\n }\n\n this.page = props.page\n this.parent = props.parent\n\n this.components = components\n this.fields = fields\n this.guidance = guidance\n\n this.formSchema = formSchema\n this.stateSchema = stateSchema\n }\n\n get keys() {\n return this.fields.flatMap((field) => {\n const { name, collection } = field\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n })\n }\n\n getFormDataFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n this.fields.forEach((component) => {\n Object.assign(payload, component.getFormDataFromState(state))\n })\n\n return payload\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const payload: FormPayload = {}\n\n // Remove name prefix for formatted value\n for (const [name, value] of Object.entries(\n this.getFormDataFromState(state)\n )) {\n const key = name.split('__').pop()\n if (!key) {\n continue\n }\n\n payload[key] = value\n }\n\n return payload\n }\n\n getStateFromValidForm(payload: FormPayload) {\n const state: FormState = {}\n\n this.fields.forEach((component) => {\n Object.assign(state, component.getStateFromValidForm(payload))\n })\n\n return state\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const context: FormState = {}\n\n for (const component of this.fields) {\n context[component.name] = component.getContextValueFromState(state)\n }\n\n return context\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { fields } = this\n\n const list: FormSubmissionError[] = []\n\n // Add only one error per field\n for (const field of fields) {\n const error = field.getError(errors)\n\n if (error) {\n list.push(error)\n }\n }\n\n if (!list.length) {\n return\n }\n\n return list\n }\n\n getViewModel(\n payload: FormPayload,\n errors?: FormSubmissionError[],\n query: FormQuery = {}\n ) {\n const { components } = this\n\n const result: ComponentViewModel[] = components.map((component) => {\n const { isFormComponent, type } = component\n\n const model =\n component instanceof FormComponent\n ? component.getViewModel(payload, errors, query)\n : component.getViewModel()\n\n return { type, isFormComponent, model }\n })\n\n return result\n }\n\n /**\n * Validate form payload\n */\n validate(value: FormPayload = {}): FormValidationResult<FormPayload> {\n const result = this.formSchema.validate(value, opts)\n const details = result.error?.details\n\n return {\n value: (result.value ?? {}) as typeof value,\n errors: this.page?.getErrors(details) ?? getErrors(details)\n }\n }\n}\n\n/**\n * Check for field local state\n */\nexport function isErrorContext(\n value?: unknown\n): value is ErrorReportCollection['local'] {\n return isFormState(value) && typeof value.label === 'string'\n}\n"],"mappings":"AACA,OAAOA,GAAG,MAIH,KAAK;AAEZ,SACEC,aAAa,EACbC,WAAW,EACXC,WAAW;AAEb,SACEC,eAAe;AAMjB,SAASC,SAAS;AAGlB,SAASC,iBAAiB,IAAIC,IAAI;AAUlC,OAAO,MAAMC,mBAAmB,CAAC;EAC/BC,IAAI;EACJC,MAAM;EAENC,UAAU;EACVC,MAAM;EACNC,QAAQ;EAERC,UAAU;EACVC,WAAW;EAEXC,WAAWA,CACTC,IAAoB,EACpBC,KAIC,EACDC,MAWC,EACD;IACA,MAAMR,UAAU,GAAGM,IAAI,CAACG,GAAG,CAAEC,GAAG,IAAKjB,eAAe,CAACiB,GAAG,EAAEH,KAAK,CAAC,CAAC;IAEjE,MAAMN,MAAM,GAAGD,UAAU,CAACW,MAAM,CAC7BC,SAAS,IAAyBA,SAAS,CAACC,eAC/C,CAAC;IAED,MAAMX,QAAQ,GAAGF,UAAU,CAACW,MAAM,CAC/BC,SAAS,IAA4B,CAACA,SAAS,CAACC,eACnD,CAAC;IAED,IAAIV,UAAU,GAAGd,GAAG,CAACyB,MAAM,CAAc,CAAC,CAACC,QAAQ,CAAC,CAAC;IACrD,IAAIX,WAAW,GAAGf,GAAG,CAACyB,MAAM,CAAsB,CAAC,CAACC,QAAQ,CAAC,CAAC;;IAE9D;IACA,KAAK,MAAMC,KAAK,IAAIf,MAAM,EAAE;MAC1B,MAAM;QAAEgB,UAAU;QAAEC;MAAK,CAAC,GAAGF,KAAK;MAElCb,UAAU,GAAGc,UAAU,GACnBd,UAAU,CAACgB,MAAM,CAACF,UAAU,CAACd,UAAU,CAAC,GACxCA,UAAU,CAACiB,IAAI,CAAC;QAAE,CAACF,IAAI,GAAGF,KAAK,CAACb;MAAW,CAAC,CAAC;MAEjDC,WAAW,GAAGa,UAAU,GACpBb,WAAW,CAACe,MAAM,CAACF,UAAU,CAACb,WAAW,CAAC,GAC1CA,WAAW,CAACgB,IAAI,CAAC;QAAE,CAACF,IAAI,GAAGF,KAAK,CAACZ;MAAY,CAAC,CAAC;IACrD;;IAEA;IACAD,UAAU,GAAGA,UAAU,CAACkB,KAAK,CAAEC,MAAM,IAAK;MACxC,OAAOA,MAAM,CAACC,OAAO,CAAEF,KAAK,IAAK;QAC/B,IAAI,CAACG,cAAc,CAACH,KAAK,CAACI,KAAK,CAAC,IAAIJ,KAAK,CAACI,KAAK,CAACC,KAAK,EAAE;UACrD,OAAOL,KAAK;QACd;;QAEA;QACA,IAAI;UAAEM,OAAO;UAAEC,GAAG,GAAGD,OAAO,GAAG,CAAC;QAAE,CAAC,GAAGN,KAAK,CAACI,KAAK;;QAEjD;QACA,IAAI,OAAOG,GAAG,KAAK,QAAQ,EAAE;UAC3BA,GAAG,GAAGP,KAAK,CAACQ,IAAI,CAAC,CAAC,CAAC;QACrB;;QAEA;QACA,MAAM9B,MAAM,GAAGE,MAAM,CAAC6B,IAAI,CACvBC,IAAI,IAAKA,IAAI,CAACb,IAAI,KAAKU,GAAG,EAAEI,KAAK,CAAC,IAAI,CAAC,CAACC,KAAK,CAAC,CACjD,CAAC;;QAED;QACA,MAAMC,KAAK,GAAG,CAACnC,MAAM,EAAEkB,UAAU,EAAEhB,MAAM,IAAIA,MAAM,EAAE6B,IAAI,CACtDC,IAAI,IAAKA,IAAI,CAACb,IAAI,KAAKU,GAC1B,CAAC;;QAED;QACA,IAAIM,KAAK,KAAK,CAACb,KAAK,CAACI,KAAK,CAACU,KAAK,IAAId,KAAK,CAACI,KAAK,CAACU,KAAK,KAAK,OAAO,CAAC,EAAE;UAClEd,KAAK,CAACI,KAAK,CAACU,KAAK,GAAGD,KAAK,CAACR,KAAK;QACjC;;QAEA;QACA,IAAIC,OAAO,EAAES,MAAM,EAAE;UACnBf,KAAK,CAACQ,IAAI,GAAGF,OAAO;UACpBN,KAAK,CAACI,KAAK,CAACG,GAAG,GAAGD,OAAO,CAAC,CAAC,CAAC;QAC9B;;QAEA;QACAN,KAAK,CAACI,KAAK,CAACC,KAAK,KAAK3B,MAAM,EAAE2B,KAAK;QAEnC,OAAOL,KAAK;MACd,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,IAAIb,MAAM,EAAE6B,KAAK,EAAE;MACjBlC,UAAU,GAAGA,UAAU,CAACmC,GAAG,CAAC,GAAG9B,MAAM,CAAC6B,KAAK,EAAE;QAC3CE,SAAS,EAAE/C;MACb,CAAC,CAAC;IACJ;IAEA,IAAIgB,MAAM,EAAEgC,MAAM,EAAE;MAClBrC,UAAU,GAAGA,UAAU,CAACqC,MAAM,CAAChC,MAAM,CAACgC,MAAM,CAAC;IAC/C;IAEA,IAAI,CAAC1C,IAAI,GAAGS,KAAK,CAACT,IAAI;IACtB,IAAI,CAACC,MAAM,GAAGQ,KAAK,CAACR,MAAM;IAE1B,IAAI,CAACC,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACC,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACC,QAAQ,GAAGA,QAAQ;IAExB,IAAI,CAACC,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACC,WAAW,GAAGA,WAAW;EAChC;EAEA,IAAIgB,IAAIA,CAAA,EAAG;IACT,OAAO,IAAI,CAACnB,MAAM,CAACsB,OAAO,CAAEP,KAAK,IAAK;MACpC,MAAM;QAAEE,IAAI;QAAED;MAAW,CAAC,GAAGD,KAAK;MAElC,IAAIC,UAAU,EAAE;QACd,MAAM;UAAEhB;QAAO,CAAC,GAAGgB,UAAU;QAC7B,OAAO,CAACC,IAAI,EAAE,GAAGjB,MAAM,CAACQ,GAAG,CAAC,CAAC;UAAES;QAAK,CAAC,KAAKA,IAAI,CAAC,CAAC;MAClD;MAEA,OAAO,CAACA,IAAI,CAAC;IACf,CAAC,CAAC;EACJ;EAEAuB,oBAAoBA,CAACC,KAA0B,EAAE;IAC/C,MAAMC,OAAoB,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC1C,MAAM,CAAC2C,OAAO,CAAEhC,SAAS,IAAK;MACjCiC,MAAM,CAACC,MAAM,CAACH,OAAO,EAAE/B,SAAS,CAAC6B,oBAAoB,CAACC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,OAAOC,OAAO;EAChB;EAEAI,qBAAqBA,CAACL,KAA0B,EAAE;IAChD,MAAMC,OAAoB,GAAG,CAAC,CAAC;;IAE/B;IACA,KAAK,MAAM,CAACzB,IAAI,EAAE8B,KAAK,CAAC,IAAIH,MAAM,CAACI,OAAO,CACxC,IAAI,CAACR,oBAAoB,CAACC,KAAK,CACjC,CAAC,EAAE;MACD,MAAMd,GAAG,GAAGV,IAAI,CAACc,KAAK,CAAC,IAAI,CAAC,CAACkB,GAAG,CAAC,CAAC;MAClC,IAAI,CAACtB,GAAG,EAAE;QACR;MACF;MAEAe,OAAO,CAACf,GAAG,CAAC,GAAGoB,KAAK;IACtB;IAEA,OAAOL,OAAO;EAChB;EAEAQ,qBAAqBA,CAACR,OAAoB,EAAE;IAC1C,MAAMD,KAAgB,GAAG,CAAC,CAAC;IAE3B,IAAI,CAACzC,MAAM,CAAC2C,OAAO,CAAEhC,SAAS,IAAK;MACjCiC,MAAM,CAACC,MAAM,CAACJ,KAAK,EAAE9B,SAAS,CAACuC,qBAAqB,CAACR,OAAO,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,OAAOD,KAAK;EACd;EAEAU,wBAAwBA,CAACV,KAA0B,EAAE;IACnD,MAAMW,OAAkB,GAAG,CAAC,CAAC;IAE7B,KAAK,MAAMzC,SAAS,IAAI,IAAI,CAACX,MAAM,EAAE;MACnCoD,OAAO,CAACzC,SAAS,CAACM,IAAI,CAAC,GAAGN,SAAS,CAACwC,wBAAwB,CAACV,KAAK,CAAC;IACrE;IAEA,OAAOW,OAAO;EAChB;EAEA3D,SAASA,CAAC4B,MAA8B,EAAqC;IAC3E,MAAM;MAAErB;IAAO,CAAC,GAAG,IAAI;IAEvB,MAAMqD,IAA2B,GAAG,EAAE;;IAEtC;IACA,KAAK,MAAMtC,KAAK,IAAIf,MAAM,EAAE;MAC1B,MAAMoB,KAAK,GAAGL,KAAK,CAACuC,QAAQ,CAACjC,MAAM,CAAC;MAEpC,IAAID,KAAK,EAAE;QACTiC,IAAI,CAACE,IAAI,CAACnC,KAAK,CAAC;MAClB;IACF;IAEA,IAAI,CAACiC,IAAI,CAAClB,MAAM,EAAE;MAChB;IACF;IAEA,OAAOkB,IAAI;EACb;EAEAG,YAAYA,CACVd,OAAoB,EACpBrB,MAA8B,EAC9BoC,KAAgB,GAAG,CAAC,CAAC,EACrB;IACA,MAAM;MAAE1D;IAAW,CAAC,GAAG,IAAI;IAE3B,MAAM2D,MAA4B,GAAG3D,UAAU,CAACS,GAAG,CAAEG,SAAS,IAAK;MACjE,MAAM;QAAEC,eAAe;QAAE+C;MAAK,CAAC,GAAGhD,SAAS;MAE3C,MAAMiD,KAAK,GACTjD,SAAS,YAAYtB,aAAa,GAC9BsB,SAAS,CAAC6C,YAAY,CAACd,OAAO,EAAErB,MAAM,EAAEoC,KAAK,CAAC,GAC9C9C,SAAS,CAAC6C,YAAY,CAAC,CAAC;MAE9B,OAAO;QAAEG,IAAI;QAAE/C,eAAe;QAAEgD;MAAM,CAAC;IACzC,CAAC,CAAC;IAEF,OAAOF,MAAM;EACf;;EAEA;AACF;AACA;EACEG,QAAQA,CAACd,KAAkB,GAAG,CAAC,CAAC,EAAqC;IACnE,MAAMW,MAAM,GAAG,IAAI,CAACxD,UAAU,CAAC2D,QAAQ,CAACd,KAAK,EAAEpD,IAAI,CAAC;IACpD,MAAMmE,OAAO,GAAGJ,MAAM,CAACtC,KAAK,EAAE0C,OAAO;IAErC,OAAO;MACLf,KAAK,EAAGW,MAAM,CAACX,KAAK,IAAI,CAAC,CAAkB;MAC3C1B,MAAM,EAAE,IAAI,CAACxB,IAAI,EAAEJ,SAAS,CAACqE,OAAO,CAAC,IAAIrE,SAAS,CAACqE,OAAO;IAC5D,CAAC;EACH;AACF;;AAEA;AACA;AACA;AACA,OAAO,SAASvC,cAAcA,CAC5BwB,KAAe,EAC0B;EACzC,OAAOzD,WAAW,CAACyD,KAAK,CAAC,IAAI,OAAOA,KAAK,CAACb,KAAK,KAAK,QAAQ;AAC9D","ignoreList":[]}
|