@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.
Files changed (615) hide show
  1. package/.browserslistrc +16 -0
  2. package/.editorconfig +9 -0
  3. package/.eslintrc.cjs +266 -0
  4. package/.github/dependabot.yml +85 -0
  5. package/.github/workflows/check-pull-request.yml +209 -0
  6. package/.github/workflows/pr-notifier.yml +98 -0
  7. package/.github/workflows/publish.yml +111 -0
  8. package/.husky/pre-commit +1 -0
  9. package/.lintstagedrc.js +4 -0
  10. package/.nvmrc +1 -0
  11. package/.prettierignore +8 -0
  12. package/.prettierrc.cjs +26 -0
  13. package/.server/client/javascripts/application.js +68 -0
  14. package/.server/client/javascripts/application.js.map +1 -0
  15. package/.server/client/javascripts/file-upload.js +292 -0
  16. package/.server/client/javascripts/file-upload.js.map +1 -0
  17. package/.server/client/stylesheets/_code.scss +33 -0
  18. package/.server/client/stylesheets/_govuk-frontend.scss +4 -0
  19. package/.server/client/stylesheets/_prose.scss +56 -0
  20. package/.server/client/stylesheets/_service-banner.scss +24 -0
  21. package/.server/client/stylesheets/_summary-list.scss +28 -0
  22. package/.server/client/stylesheets/_tag-env.scss +24 -0
  23. package/.server/client/stylesheets/application.scss +14 -0
  24. package/.server/common/cookies.js +55 -0
  25. package/.server/common/cookies.js.map +1 -0
  26. package/.server/common/cookies.test.js +15 -0
  27. package/.server/common/cookies.test.js.map +1 -0
  28. package/.server/common/types.js +6 -0
  29. package/.server/common/types.js.map +1 -0
  30. package/.server/config/index.js +241 -0
  31. package/.server/config/index.js.map +1 -0
  32. package/.server/index.js +25 -0
  33. package/.server/index.js.map +1 -0
  34. package/.server/server/common/helpers/logging/logger-options.js +44 -0
  35. package/.server/server/common/helpers/logging/logger-options.js.map +1 -0
  36. package/.server/server/common/helpers/logging/logger.js +6 -0
  37. package/.server/server/common/helpers/logging/logger.js.map +1 -0
  38. package/.server/server/common/helpers/logging/request-logger.js +7 -0
  39. package/.server/server/common/helpers/logging/request-logger.js.map +1 -0
  40. package/.server/server/common/helpers/logging/request-tracing.js +12 -0
  41. package/.server/server/common/helpers/logging/request-tracing.js.map +1 -0
  42. package/.server/server/common/helpers/redis-client.js +55 -0
  43. package/.server/server/common/helpers/redis-client.js.map +1 -0
  44. package/.server/server/constants.js +2 -0
  45. package/.server/server/constants.js.map +1 -0
  46. package/.server/server/forms/README.md +10 -0
  47. package/.server/server/forms/components.json +1015 -0
  48. package/.server/server/forms/report-a-terrorist.json +270 -0
  49. package/.server/server/forms/runner-components-test.json +365 -0
  50. package/.server/server/forms/test.json +581 -0
  51. package/.server/server/index.js +116 -0
  52. package/.server/server/index.js.map +1 -0
  53. package/.server/server/plugins/blankie.js +29 -0
  54. package/.server/server/plugins/blankie.js.map +1 -0
  55. package/.server/server/plugins/crumb.js +15 -0
  56. package/.server/server/plugins/crumb.js.map +1 -0
  57. package/.server/server/plugins/engine/README.md +87 -0
  58. package/.server/server/plugins/engine/components/AutocompleteField.js +37 -0
  59. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -0
  60. package/.server/server/plugins/engine/components/CheckboxesField.js +79 -0
  61. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -0
  62. package/.server/server/plugins/engine/components/ComponentBase.js +55 -0
  63. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -0
  64. package/.server/server/plugins/engine/components/ComponentCollection.js +198 -0
  65. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -0
  66. package/.server/server/plugins/engine/components/DatePartsField.js +208 -0
  67. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -0
  68. package/.server/server/plugins/engine/components/Details.js +26 -0
  69. package/.server/server/plugins/engine/components/Details.js.map +1 -0
  70. package/.server/server/plugins/engine/components/EmailAddressField.js +40 -0
  71. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -0
  72. package/.server/server/plugins/engine/components/FileUploadField.js +195 -0
  73. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -0
  74. package/.server/server/plugins/engine/components/FormComponent.js +210 -0
  75. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -0
  76. package/.server/server/plugins/engine/components/Html.js +24 -0
  77. package/.server/server/plugins/engine/components/Html.js.map +1 -0
  78. package/.server/server/plugins/engine/components/InsetText.js +22 -0
  79. package/.server/server/plugins/engine/components/InsetText.js.map +1 -0
  80. package/.server/server/plugins/engine/components/List.js +65 -0
  81. package/.server/server/plugins/engine/components/List.js.map +1 -0
  82. package/.server/server/plugins/engine/components/ListFormComponent.js +87 -0
  83. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -0
  84. package/.server/server/plugins/engine/components/MonthYearField.js +172 -0
  85. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -0
  86. package/.server/server/plugins/engine/components/MultilineTextField.js +115 -0
  87. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -0
  88. package/.server/server/plugins/engine/components/NumberField.js +137 -0
  89. package/.server/server/plugins/engine/components/NumberField.js.map +1 -0
  90. package/.server/server/plugins/engine/components/RadiosField.js +18 -0
  91. package/.server/server/plugins/engine/components/RadiosField.js.map +1 -0
  92. package/.server/server/plugins/engine/components/SelectField.js +33 -0
  93. package/.server/server/plugins/engine/components/SelectField.js.map +1 -0
  94. package/.server/server/plugins/engine/components/SelectionControlField.js +43 -0
  95. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -0
  96. package/.server/server/plugins/engine/components/TelephoneNumberField.js +43 -0
  97. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -0
  98. package/.server/server/plugins/engine/components/TextField.js +63 -0
  99. package/.server/server/plugins/engine/components/TextField.js.map +1 -0
  100. package/.server/server/plugins/engine/components/UkAddressField.js +130 -0
  101. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -0
  102. package/.server/server/plugins/engine/components/YesNoField.js +28 -0
  103. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -0
  104. package/.server/server/plugins/engine/components/constants.js +2 -0
  105. package/.server/server/plugins/engine/components/constants.js.map +1 -0
  106. package/.server/server/plugins/engine/components/helpers.js +219 -0
  107. package/.server/server/plugins/engine/components/helpers.js.map +1 -0
  108. package/.server/server/plugins/engine/components/index.js +25 -0
  109. package/.server/server/plugins/engine/components/index.js.map +1 -0
  110. package/.server/server/plugins/engine/components/types.js +2 -0
  111. package/.server/server/plugins/engine/components/types.js.map +1 -0
  112. package/.server/server/plugins/engine/configureEnginePlugin.js +44 -0
  113. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -0
  114. package/.server/server/plugins/engine/helpers.js +268 -0
  115. package/.server/server/plugins/engine/helpers.js.map +1 -0
  116. package/.server/server/plugins/engine/index.js +6 -0
  117. package/.server/server/plugins/engine/index.js.map +1 -0
  118. package/.server/server/plugins/engine/models/FormModel.js +363 -0
  119. package/.server/server/plugins/engine/models/FormModel.js.map +1 -0
  120. package/.server/server/plugins/engine/models/RepeatingSummaryViewModel.js +2 -0
  121. package/.server/server/plugins/engine/models/RepeatingSummaryViewModel.js.map +1 -0
  122. package/.server/server/plugins/engine/models/Section.js +2 -0
  123. package/.server/server/plugins/engine/models/Section.js.map +1 -0
  124. package/.server/server/plugins/engine/models/SummaryViewModel.js +183 -0
  125. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -0
  126. package/.server/server/plugins/engine/models/index.js +3 -0
  127. package/.server/server/plugins/engine/models/index.js.map +1 -0
  128. package/.server/server/plugins/engine/models/types.js +2 -0
  129. package/.server/server/plugins/engine/models/types.js.map +1 -0
  130. package/.server/server/plugins/engine/outputFormatters/human/v1.js +44 -0
  131. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -0
  132. package/.server/server/plugins/engine/outputFormatters/index.js +24 -0
  133. package/.server/server/plugins/engine/outputFormatters/index.js.map +1 -0
  134. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +104 -0
  135. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -0
  136. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +110 -0
  137. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -0
  138. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +401 -0
  139. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -0
  140. package/.server/server/plugins/engine/pageControllers/PageController.js +133 -0
  141. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -0
  142. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +482 -0
  143. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -0
  144. package/.server/server/plugins/engine/pageControllers/README.md +28 -0
  145. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +372 -0
  146. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -0
  147. package/.server/server/plugins/engine/pageControllers/StartPageController.js +16 -0
  148. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -0
  149. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +43 -0
  150. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -0
  151. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +195 -0
  152. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -0
  153. package/.server/server/plugins/engine/pageControllers/TerminalPageController.js +8 -0
  154. package/.server/server/plugins/engine/pageControllers/TerminalPageController.js.map +1 -0
  155. package/.server/server/plugins/engine/pageControllers/helpers.js +69 -0
  156. package/.server/server/plugins/engine/pageControllers/helpers.js.map +1 -0
  157. package/.server/server/plugins/engine/pageControllers/index.js +10 -0
  158. package/.server/server/plugins/engine/pageControllers/index.js.map +1 -0
  159. package/.server/server/plugins/engine/pageControllers/validationOptions.js +78 -0
  160. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -0
  161. package/.server/server/plugins/engine/plugin.js +562 -0
  162. package/.server/server/plugins/engine/plugin.js.map +1 -0
  163. package/.server/server/plugins/engine/services/formSubmissionService.js +39 -0
  164. package/.server/server/plugins/engine/services/formSubmissionService.js.map +1 -0
  165. package/.server/server/plugins/engine/services/formsService.js +41 -0
  166. package/.server/server/plugins/engine/services/formsService.js.map +1 -0
  167. package/.server/server/plugins/engine/services/formsService.test.js +71 -0
  168. package/.server/server/plugins/engine/services/formsService.test.js.map +1 -0
  169. package/.server/server/plugins/engine/services/index.js +4 -0
  170. package/.server/server/plugins/engine/services/index.js.map +1 -0
  171. package/.server/server/plugins/engine/services/notifyService.js +45 -0
  172. package/.server/server/plugins/engine/services/notifyService.js.map +1 -0
  173. package/.server/server/plugins/engine/services/uploadService.js +51 -0
  174. package/.server/server/plugins/engine/services/uploadService.js.map +1 -0
  175. package/.server/server/plugins/engine/types.js +53 -0
  176. package/.server/server/plugins/engine/types.js.map +1 -0
  177. package/.server/server/plugins/engine/views/components/autocompletefield.html +5 -0
  178. package/.server/server/plugins/engine/views/components/checkboxesfield.html +5 -0
  179. package/.server/server/plugins/engine/views/components/datepartsfield.html +5 -0
  180. package/.server/server/plugins/engine/views/components/details.html +6 -0
  181. package/.server/server/plugins/engine/views/components/emailaddressfield.html +5 -0
  182. package/.server/server/plugins/engine/views/components/fileuploadfield-key.html +8 -0
  183. package/.server/server/plugins/engine/views/components/fileuploadfield-value.html +3 -0
  184. package/.server/server/plugins/engine/views/components/fileuploadfield.html +24 -0
  185. package/.server/server/plugins/engine/views/components/html.html +3 -0
  186. package/.server/server/plugins/engine/views/components/insettext.html +7 -0
  187. package/.server/server/plugins/engine/views/components/list.html +36 -0
  188. package/.server/server/plugins/engine/views/components/monthyearfield.html +5 -0
  189. package/.server/server/plugins/engine/views/components/multilinetextfield.html +10 -0
  190. package/.server/server/plugins/engine/views/components/numberfield.html +5 -0
  191. package/.server/server/plugins/engine/views/components/radiosfield.html +5 -0
  192. package/.server/server/plugins/engine/views/components/selectfield.html +5 -0
  193. package/.server/server/plugins/engine/views/components/telephonenumberfield.html +5 -0
  194. package/.server/server/plugins/engine/views/components/textfield.html +5 -0
  195. package/.server/server/plugins/engine/views/components/ukaddressfield.html +25 -0
  196. package/.server/server/plugins/engine/views/components/yesnofield.html +5 -0
  197. package/.server/server/plugins/engine/views/file-upload.html +45 -0
  198. package/.server/server/plugins/engine/views/index.html +39 -0
  199. package/.server/server/plugins/engine/views/item-delete.html +56 -0
  200. package/.server/server/plugins/engine/views/partials/components.html +6 -0
  201. package/.server/server/plugins/engine/views/partials/conditional-components.html +3 -0
  202. package/.server/server/plugins/engine/views/partials/debug.html +44 -0
  203. package/.server/server/plugins/engine/views/partials/form.html +15 -0
  204. package/.server/server/plugins/engine/views/partials/heading.html +16 -0
  205. package/.server/server/plugins/engine/views/partials/preview-banner.html +32 -0
  206. package/.server/server/plugins/engine/views/partials/preview-banner.test.js +108 -0
  207. package/.server/server/plugins/engine/views/partials/preview-banner.test.js.map +1 -0
  208. package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +10 -0
  209. package/.server/server/plugins/engine/views/repeat-list-summary.html +53 -0
  210. package/.server/server/plugins/errorPages.js +49 -0
  211. package/.server/server/plugins/errorPages.js.map +1 -0
  212. package/.server/server/plugins/nunjucks/context.js +79 -0
  213. package/.server/server/plugins/nunjucks/context.js.map +1 -0
  214. package/.server/server/plugins/nunjucks/context.test.js +134 -0
  215. package/.server/server/plugins/nunjucks/context.test.js.map +1 -0
  216. package/.server/server/plugins/nunjucks/enviroment.test.js +166 -0
  217. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -0
  218. package/.server/server/plugins/nunjucks/environment.js +95 -0
  219. package/.server/server/plugins/nunjucks/environment.js.map +1 -0
  220. package/.server/server/plugins/nunjucks/filters/answer.js +26 -0
  221. package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -0
  222. package/.server/server/plugins/nunjucks/filters/answer.test.js +70 -0
  223. package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -0
  224. package/.server/server/plugins/nunjucks/filters/evaluate.js +22 -0
  225. package/.server/server/plugins/nunjucks/filters/evaluate.js.map +1 -0
  226. package/.server/server/plugins/nunjucks/filters/field.js +26 -0
  227. package/.server/server/plugins/nunjucks/filters/field.js.map +1 -0
  228. package/.server/server/plugins/nunjucks/filters/field.test.js +64 -0
  229. package/.server/server/plugins/nunjucks/filters/field.test.js.map +1 -0
  230. package/.server/server/plugins/nunjucks/filters/highlight.js +14 -0
  231. package/.server/server/plugins/nunjucks/filters/highlight.js.map +1 -0
  232. package/.server/server/plugins/nunjucks/filters/href.js +28 -0
  233. package/.server/server/plugins/nunjucks/filters/href.js.map +1 -0
  234. package/.server/server/plugins/nunjucks/filters/href.test.js +63 -0
  235. package/.server/server/plugins/nunjucks/filters/href.test.js.map +1 -0
  236. package/.server/server/plugins/nunjucks/filters/index.js +9 -0
  237. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -0
  238. package/.server/server/plugins/nunjucks/filters/inspect.js +16 -0
  239. package/.server/server/plugins/nunjucks/filters/inspect.js.map +1 -0
  240. package/.server/server/plugins/nunjucks/filters/page.js +23 -0
  241. package/.server/server/plugins/nunjucks/filters/page.js.map +1 -0
  242. package/.server/server/plugins/nunjucks/filters/page.test.js +51 -0
  243. package/.server/server/plugins/nunjucks/filters/page.test.js.map +1 -0
  244. package/.server/server/plugins/nunjucks/index.js +4 -0
  245. package/.server/server/plugins/nunjucks/index.js.map +1 -0
  246. package/.server/server/plugins/nunjucks/plugin.js +38 -0
  247. package/.server/server/plugins/nunjucks/plugin.js.map +1 -0
  248. package/.server/server/plugins/nunjucks/render.js +41 -0
  249. package/.server/server/plugins/nunjucks/render.js.map +1 -0
  250. package/.server/server/plugins/nunjucks/types.js +41 -0
  251. package/.server/server/plugins/nunjucks/types.js.map +1 -0
  252. package/.server/server/plugins/pulse.js +8 -0
  253. package/.server/server/plugins/pulse.js.map +1 -0
  254. package/.server/server/plugins/router.js +169 -0
  255. package/.server/server/plugins/router.js.map +1 -0
  256. package/.server/server/plugins/session.js +28 -0
  257. package/.server/server/plugins/session.js.map +1 -0
  258. package/.server/server/routes/health.js +15 -0
  259. package/.server/server/routes/health.js.map +1 -0
  260. package/.server/server/routes/health.test.js +32 -0
  261. package/.server/server/routes/health.test.js.map +1 -0
  262. package/.server/server/routes/index.js +3 -0
  263. package/.server/server/routes/index.js.map +1 -0
  264. package/.server/server/routes/public.js +37 -0
  265. package/.server/server/routes/public.js.map +1 -0
  266. package/.server/server/routes/types.js +14 -0
  267. package/.server/server/routes/types.js.map +1 -0
  268. package/.server/server/schemas/index.js +15 -0
  269. package/.server/server/schemas/index.js.map +1 -0
  270. package/.server/server/secure-context.js +36 -0
  271. package/.server/server/secure-context.js.map +1 -0
  272. package/.server/server/services/cacheService.js +85 -0
  273. package/.server/server/services/cacheService.js.map +1 -0
  274. package/.server/server/services/httpService.js +44 -0
  275. package/.server/server/services/httpService.js.map +1 -0
  276. package/.server/server/services/httpService.test.js +504 -0
  277. package/.server/server/services/httpService.test.js.map +1 -0
  278. package/.server/server/services/index.js +2 -0
  279. package/.server/server/services/index.js.map +1 -0
  280. package/.server/server/types.js +2 -0
  281. package/.server/server/types.js.map +1 -0
  282. package/.server/server/utils/notify.js +40 -0
  283. package/.server/server/utils/notify.js.map +1 -0
  284. package/.server/server/utils/secure-context/get-trust-store-certs.js +7 -0
  285. package/.server/server/utils/secure-context/get-trust-store-certs.js.map +1 -0
  286. package/.server/server/utils/secure-context/get-trust-store-certs.test.js +14 -0
  287. package/.server/server/utils/secure-context/get-trust-store-certs.test.js.map +1 -0
  288. package/.server/server/utils/utils.js +20 -0
  289. package/.server/server/utils/utils.js.map +1 -0
  290. package/.server/server/utils/utils.test.js +49 -0
  291. package/.server/server/utils/utils.test.js.map +1 -0
  292. package/.server/server/views/404.html +16 -0
  293. package/.server/server/views/500.html +19 -0
  294. package/.server/server/views/components/debug/macro.njk +3 -0
  295. package/.server/server/views/components/debug/template.njk +13 -0
  296. package/.server/server/views/components/service-banner/macro.njk +3 -0
  297. package/.server/server/views/components/service-banner/template.njk +20 -0
  298. package/.server/server/views/components/service-banner/template.test.js +36 -0
  299. package/.server/server/views/components/service-banner/template.test.js.map +1 -0
  300. package/.server/server/views/components/tag-env/macro.njk +3 -0
  301. package/.server/server/views/components/tag-env/template.njk +30 -0
  302. package/.server/server/views/components/tag-env/template.test.js +59 -0
  303. package/.server/server/views/components/tag-env/template.test.js.map +1 -0
  304. package/.server/server/views/confirmation.html +19 -0
  305. package/.server/server/views/help/accessibility-statement.html +58 -0
  306. package/.server/server/views/help/cookie-preferences.html +57 -0
  307. package/.server/server/views/help/cookies.html +71 -0
  308. package/.server/server/views/help/get-support.html +37 -0
  309. package/.server/server/views/help/privacy-notice.html +68 -0
  310. package/.server/server/views/help/terms-and-conditions.html +83 -0
  311. package/.server/server/views/layout.html +199 -0
  312. package/.server/server/views/summary.html +50 -0
  313. package/.server/typings/hapi/index.d.js +2 -0
  314. package/.server/typings/hapi/index.d.js.map +1 -0
  315. package/.server/typings/hapi-tracing/index.d.js +2 -0
  316. package/.server/typings/hapi-tracing/index.d.js.map +1 -0
  317. package/.server/typings/index.d.js +2 -0
  318. package/.server/typings/index.d.js.map +1 -0
  319. package/.server/typings/joi/index.d.js +2 -0
  320. package/.server/typings/joi/index.d.js.map +1 -0
  321. package/Dockerfile +61 -0
  322. package/LICENCE +8 -0
  323. package/Procfile +1 -0
  324. package/README.md +87 -0
  325. package/babel.config.cjs +55 -0
  326. package/compose/aws.env +4 -0
  327. package/compose/start-localstack.sh +26 -0
  328. package/docker-compose.yaml +86 -0
  329. package/globals.d.ts +1 -0
  330. package/jest.config.cjs +54 -0
  331. package/jest.environment.js +4 -0
  332. package/jest.setup.cjs +14 -0
  333. package/package.json +163 -0
  334. package/postcss.config.js +26 -0
  335. package/sonar-project.properties +17 -0
  336. package/src/client/javascripts/application.js +87 -0
  337. package/src/client/javascripts/file-upload.js +386 -0
  338. package/src/client/stylesheets/_code.scss +33 -0
  339. package/src/client/stylesheets/_govuk-frontend.scss +4 -0
  340. package/src/client/stylesheets/_prose.scss +56 -0
  341. package/src/client/stylesheets/_service-banner.scss +24 -0
  342. package/src/client/stylesheets/_summary-list.scss +28 -0
  343. package/src/client/stylesheets/_tag-env.scss +24 -0
  344. package/src/client/stylesheets/application.scss +14 -0
  345. package/src/common/cookies.js +58 -0
  346. package/src/common/cookies.test.js +23 -0
  347. package/src/common/types.js +5 -0
  348. package/src/config/index.ts +271 -0
  349. package/src/index.ts +31 -0
  350. package/src/server/common/helpers/logging/logger-options.test.ts +50 -0
  351. package/src/server/common/helpers/logging/logger-options.ts +46 -0
  352. package/src/server/common/helpers/logging/logger.ts +7 -0
  353. package/src/server/common/helpers/logging/request-logger.ts +9 -0
  354. package/src/server/common/helpers/logging/request-tracing.js +10 -0
  355. package/src/server/common/helpers/redis-client.js +70 -0
  356. package/src/server/constants.js +1 -0
  357. package/src/server/forms/README.md +10 -0
  358. package/src/server/forms/components.json +1015 -0
  359. package/src/server/forms/report-a-terrorist.json +270 -0
  360. package/src/server/forms/runner-components-test.json +365 -0
  361. package/src/server/forms/test.json +581 -0
  362. package/src/server/index.test.ts +582 -0
  363. package/src/server/index.ts +140 -0
  364. package/src/server/plugins/blankie.test.ts +73 -0
  365. package/src/server/plugins/blankie.ts +48 -0
  366. package/src/server/plugins/crumb.ts +20 -0
  367. package/src/server/plugins/engine/README.md +87 -0
  368. package/src/server/plugins/engine/components/AutocompleteField.test.ts +294 -0
  369. package/src/server/plugins/engine/components/AutocompleteField.ts +49 -0
  370. package/src/server/plugins/engine/components/CheckboxesField.test.ts +379 -0
  371. package/src/server/plugins/engine/components/CheckboxesField.ts +106 -0
  372. package/src/server/plugins/engine/components/ComponentBase.ts +97 -0
  373. package/src/server/plugins/engine/components/ComponentCollection.ts +278 -0
  374. package/src/server/plugins/engine/components/DatePartsField.test.ts +822 -0
  375. package/src/server/plugins/engine/components/DatePartsField.ts +264 -0
  376. package/src/server/plugins/engine/components/Details.test.ts +49 -0
  377. package/src/server/plugins/engine/components/Details.ts +30 -0
  378. package/src/server/plugins/engine/components/EmailAddressField.test.ts +395 -0
  379. package/src/server/plugins/engine/components/EmailAddressField.ts +55 -0
  380. package/src/server/plugins/engine/components/FileUploadField.test.ts +778 -0
  381. package/src/server/plugins/engine/components/FileUploadField.ts +262 -0
  382. package/src/server/plugins/engine/components/FormComponent.ts +249 -0
  383. package/src/server/plugins/engine/components/Html.test.ts +48 -0
  384. package/src/server/plugins/engine/components/Html.ts +29 -0
  385. package/src/server/plugins/engine/components/InsetText.test.ts +48 -0
  386. package/src/server/plugins/engine/components/InsetText.ts +27 -0
  387. package/src/server/plugins/engine/components/List.test.ts +76 -0
  388. package/src/server/plugins/engine/components/List.ts +72 -0
  389. package/src/server/plugins/engine/components/ListFormComponent.ts +140 -0
  390. package/src/server/plugins/engine/components/MonthYearField.test.ts +567 -0
  391. package/src/server/plugins/engine/components/MonthYearField.ts +222 -0
  392. package/src/server/plugins/engine/components/MultilineTextField.test.ts +558 -0
  393. package/src/server/plugins/engine/components/MultilineTextField.ts +138 -0
  394. package/src/server/plugins/engine/components/NumberField.test.ts +701 -0
  395. package/src/server/plugins/engine/components/NumberField.ts +163 -0
  396. package/src/server/plugins/engine/components/RadiosField.test.ts +288 -0
  397. package/src/server/plugins/engine/components/RadiosField.ts +24 -0
  398. package/src/server/plugins/engine/components/SelectField.test.ts +288 -0
  399. package/src/server/plugins/engine/components/SelectField.ts +47 -0
  400. package/src/server/plugins/engine/components/SelectionControlField.ts +43 -0
  401. package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +356 -0
  402. package/src/server/plugins/engine/components/TelephoneNumberField.ts +67 -0
  403. package/src/server/plugins/engine/components/TextField.test.ts +489 -0
  404. package/src/server/plugins/engine/components/TextField.ts +96 -0
  405. package/src/server/plugins/engine/components/UkAddressField.test.ts +623 -0
  406. package/src/server/plugins/engine/components/UkAddressField.ts +172 -0
  407. package/src/server/plugins/engine/components/YesNoField.test.ts +248 -0
  408. package/src/server/plugins/engine/components/YesNoField.ts +31 -0
  409. package/src/server/plugins/engine/components/constants.ts +1 -0
  410. package/src/server/plugins/engine/components/helpers.ts +330 -0
  411. package/src/server/plugins/engine/components/index.ts +24 -0
  412. package/src/server/plugins/engine/components/types.ts +117 -0
  413. package/src/server/plugins/engine/configureEnginePlugin.ts +47 -0
  414. package/src/server/plugins/engine/helpers.test.ts +791 -0
  415. package/src/server/plugins/engine/helpers.ts +379 -0
  416. package/src/server/plugins/engine/index.ts +7 -0
  417. package/src/server/plugins/engine/models/FormModel.test.ts +42 -0
  418. package/src/server/plugins/engine/models/FormModel.ts +443 -0
  419. package/src/server/plugins/engine/models/RepeatingSummaryViewModel.ts +0 -0
  420. package/src/server/plugins/engine/models/Section.ts +0 -0
  421. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +209 -0
  422. package/src/server/plugins/engine/models/SummaryViewModel.ts +220 -0
  423. package/src/server/plugins/engine/models/index.ts +2 -0
  424. package/src/server/plugins/engine/models/types.ts +114 -0
  425. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +143 -0
  426. package/src/server/plugins/engine/outputFormatters/human/v1.ts +73 -0
  427. package/src/server/plugins/engine/outputFormatters/index.test.ts +17 -0
  428. package/src/server/plugins/engine/outputFormatters/index.ts +44 -0
  429. package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +229 -0
  430. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +140 -0
  431. package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +229 -0
  432. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +153 -0
  433. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1108 -0
  434. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +446 -0
  435. package/src/server/plugins/engine/pageControllers/PageController.test.ts +205 -0
  436. package/src/server/plugins/engine/pageControllers/PageController.ts +176 -0
  437. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +1264 -0
  438. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +561 -0
  439. package/src/server/plugins/engine/pageControllers/README.md +28 -0
  440. package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +264 -0
  441. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +458 -0
  442. package/src/server/plugins/engine/pageControllers/StartPageController.ts +18 -0
  443. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +50 -0
  444. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +261 -0
  445. package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +28 -0
  446. package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +19 -0
  447. package/src/server/plugins/engine/pageControllers/helpers.test.ts +198 -0
  448. package/src/server/plugins/engine/pageControllers/helpers.ts +101 -0
  449. package/src/server/plugins/engine/pageControllers/index.ts +10 -0
  450. package/src/server/plugins/engine/pageControllers/validationOptions.ts +89 -0
  451. package/src/server/plugins/engine/plugin.ts +673 -0
  452. package/src/server/plugins/engine/services/formSubmissionService.js +46 -0
  453. package/src/server/plugins/engine/services/formsService.js +46 -0
  454. package/src/server/plugins/engine/services/formsService.test.js +90 -0
  455. package/src/server/plugins/engine/services/index.js +3 -0
  456. package/src/server/plugins/engine/services/notifyService.test.ts +132 -0
  457. package/src/server/plugins/engine/services/notifyService.ts +64 -0
  458. package/src/server/plugins/engine/services/uploadService.js +60 -0
  459. package/src/server/plugins/engine/types.ts +315 -0
  460. package/src/server/plugins/engine/views/components/autocompletefield.html +5 -0
  461. package/src/server/plugins/engine/views/components/checkboxesfield.html +5 -0
  462. package/src/server/plugins/engine/views/components/datepartsfield.html +5 -0
  463. package/src/server/plugins/engine/views/components/details.html +6 -0
  464. package/src/server/plugins/engine/views/components/emailaddressfield.html +5 -0
  465. package/src/server/plugins/engine/views/components/fileuploadfield-key.html +8 -0
  466. package/src/server/plugins/engine/views/components/fileuploadfield-value.html +3 -0
  467. package/src/server/plugins/engine/views/components/fileuploadfield.html +24 -0
  468. package/src/server/plugins/engine/views/components/html.html +3 -0
  469. package/src/server/plugins/engine/views/components/insettext.html +7 -0
  470. package/src/server/plugins/engine/views/components/list.html +36 -0
  471. package/src/server/plugins/engine/views/components/monthyearfield.html +5 -0
  472. package/src/server/plugins/engine/views/components/multilinetextfield.html +10 -0
  473. package/src/server/plugins/engine/views/components/numberfield.html +5 -0
  474. package/src/server/plugins/engine/views/components/radiosfield.html +5 -0
  475. package/src/server/plugins/engine/views/components/selectfield.html +5 -0
  476. package/src/server/plugins/engine/views/components/telephonenumberfield.html +5 -0
  477. package/src/server/plugins/engine/views/components/textfield.html +5 -0
  478. package/src/server/plugins/engine/views/components/ukaddressfield.html +25 -0
  479. package/src/server/plugins/engine/views/components/yesnofield.html +5 -0
  480. package/src/server/plugins/engine/views/file-upload.html +45 -0
  481. package/src/server/plugins/engine/views/index.html +39 -0
  482. package/src/server/plugins/engine/views/item-delete.html +56 -0
  483. package/src/server/plugins/engine/views/partials/components.html +6 -0
  484. package/src/server/plugins/engine/views/partials/conditional-components.html +3 -0
  485. package/src/server/plugins/engine/views/partials/debug.html +44 -0
  486. package/src/server/plugins/engine/views/partials/form.html +15 -0
  487. package/src/server/plugins/engine/views/partials/heading.html +16 -0
  488. package/src/server/plugins/engine/views/partials/preview-banner.html +32 -0
  489. package/src/server/plugins/engine/views/partials/preview-banner.test.js +122 -0
  490. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +10 -0
  491. package/src/server/plugins/engine/views/repeat-list-summary.html +53 -0
  492. package/src/server/plugins/errorPages.ts +58 -0
  493. package/src/server/plugins/nunjucks/context.js +88 -0
  494. package/src/server/plugins/nunjucks/context.test.js +142 -0
  495. package/src/server/plugins/nunjucks/enviroment.test.js +201 -0
  496. package/src/server/plugins/nunjucks/environment.js +116 -0
  497. package/src/server/plugins/nunjucks/filters/answer.js +27 -0
  498. package/src/server/plugins/nunjucks/filters/answer.test.js +89 -0
  499. package/src/server/plugins/nunjucks/filters/evaluate.js +21 -0
  500. package/src/server/plugins/nunjucks/filters/field.js +28 -0
  501. package/src/server/plugins/nunjucks/filters/field.test.js +75 -0
  502. package/src/server/plugins/nunjucks/filters/highlight.js +11 -0
  503. package/src/server/plugins/nunjucks/filters/href.js +30 -0
  504. package/src/server/plugins/nunjucks/filters/href.test.js +80 -0
  505. package/src/server/plugins/nunjucks/filters/index.js +8 -0
  506. package/src/server/plugins/nunjucks/filters/inspect.js +15 -0
  507. package/src/server/plugins/nunjucks/filters/page.js +24 -0
  508. package/src/server/plugins/nunjucks/filters/page.test.js +65 -0
  509. package/src/server/plugins/nunjucks/index.js +3 -0
  510. package/src/server/plugins/nunjucks/plugin.js +40 -0
  511. package/src/server/plugins/nunjucks/render.js +42 -0
  512. package/src/server/plugins/nunjucks/types.js +40 -0
  513. package/src/server/plugins/pulse.ts +11 -0
  514. package/src/server/plugins/router.ts +201 -0
  515. package/src/server/plugins/session.ts +28 -0
  516. package/src/server/routes/health.js +13 -0
  517. package/src/server/routes/health.test.js +35 -0
  518. package/src/server/routes/index.test.ts +125 -0
  519. package/src/server/routes/index.ts +2 -0
  520. package/src/server/routes/public.ts +47 -0
  521. package/src/server/routes/types.ts +48 -0
  522. package/src/server/schemas/index.ts +34 -0
  523. package/src/server/secure-context.js +43 -0
  524. package/src/server/services/cacheService.test.ts +276 -0
  525. package/src/server/services/cacheService.ts +131 -0
  526. package/src/server/services/httpService.test.js +491 -0
  527. package/src/server/services/httpService.ts +50 -0
  528. package/src/server/services/index.ts +1 -0
  529. package/src/server/types.ts +54 -0
  530. package/src/server/utils/notify.test.ts +37 -0
  531. package/src/server/utils/notify.ts +50 -0
  532. package/src/server/utils/secure-context/get-trust-store-certs.js +11 -0
  533. package/src/server/utils/secure-context/get-trust-store-certs.test.js +19 -0
  534. package/src/server/utils/utils.js +24 -0
  535. package/src/server/utils/utils.test.js +54 -0
  536. package/src/server/views/404.html +16 -0
  537. package/src/server/views/500.html +19 -0
  538. package/src/server/views/components/debug/macro.njk +3 -0
  539. package/src/server/views/components/debug/template.njk +13 -0
  540. package/src/server/views/components/service-banner/macro.njk +3 -0
  541. package/src/server/views/components/service-banner/template.njk +20 -0
  542. package/src/server/views/components/service-banner/template.test.js +43 -0
  543. package/src/server/views/components/tag-env/macro.njk +3 -0
  544. package/src/server/views/components/tag-env/template.njk +30 -0
  545. package/src/server/views/components/tag-env/template.test.js +66 -0
  546. package/src/server/views/confirmation.html +19 -0
  547. package/src/server/views/help/accessibility-statement.html +58 -0
  548. package/src/server/views/help/cookie-preferences.html +57 -0
  549. package/src/server/views/help/cookies.html +71 -0
  550. package/src/server/views/help/get-support.html +37 -0
  551. package/src/server/views/help/privacy-notice.html +68 -0
  552. package/src/server/views/help/terms-and-conditions.html +83 -0
  553. package/src/server/views/layout.html +199 -0
  554. package/src/server/views/summary.html +50 -0
  555. package/src/typings/hapi/index.d.ts +95 -0
  556. package/src/typings/hapi-tracing/index.d.ts +6 -0
  557. package/src/typings/index.d.ts +3 -0
  558. package/src/typings/joi/index.d.ts +22 -0
  559. package/stylelint.config.js +10 -0
  560. package/test/client/javascripts/file-upload.test.js +1197 -0
  561. package/test/condition/checkboxes.test.js +112 -0
  562. package/test/condition/radios.test.js +112 -0
  563. package/test/condition/text.test.js +103 -0
  564. package/test/fixtures/assets-manifest.json +4 -0
  565. package/test/fixtures/form.js +86 -0
  566. package/test/fixtures/index.js +2 -0
  567. package/test/fixtures/list.js +92 -0
  568. package/test/form/cookies.test.js +338 -0
  569. package/test/form/csrf.test.js +87 -0
  570. package/test/form/definitions/basic.js +101 -0
  571. package/test/form/definitions/blank.js +10 -0
  572. package/test/form/definitions/checkboxes.json +88 -0
  573. package/test/form/definitions/components.json +452 -0
  574. package/test/form/definitions/conditional-reveal.js +140 -0
  575. package/test/form/definitions/conditions-basic.js +187 -0
  576. package/test/form/definitions/conditions-complex.js +338 -0
  577. package/test/form/definitions/conditions-dates.js +78 -0
  578. package/test/form/definitions/conditions-escaping.js +143 -0
  579. package/test/form/definitions/demo-cph-number.js +3099 -0
  580. package/test/form/definitions/feedback.json +45 -0
  581. package/test/form/definitions/fields-optional.js +402 -0
  582. package/test/form/definitions/fields-required.js +402 -0
  583. package/test/form/definitions/file-upload-basic.js +44 -0
  584. package/test/form/definitions/file-upload.js +66 -0
  585. package/test/form/definitions/minimal.js +39 -0
  586. package/test/form/definitions/phase-alpha.json +33 -0
  587. package/test/form/definitions/phase-default.json +26 -0
  588. package/test/form/definitions/radios.json +88 -0
  589. package/test/form/definitions/repeat-mixed.js +54 -0
  590. package/test/form/definitions/repeat.js +70 -0
  591. package/test/form/definitions/status.json +126 -0
  592. package/test/form/definitions/templates.js +183 -0
  593. package/test/form/definitions/test.json +581 -0
  594. package/test/form/definitions/text.json +75 -0
  595. package/test/form/definitions/titles.json +170 -0
  596. package/test/form/definitions.test.js +47 -0
  597. package/test/form/exit-page.test.js +210 -0
  598. package/test/form/feedback.test.js +68 -0
  599. package/test/form/fields-optional.test.js +237 -0
  600. package/test/form/fields-required.test.js +294 -0
  601. package/test/form/file-upload.test.js +313 -0
  602. package/test/form/govuk-notify.test.js +449 -0
  603. package/test/form/journey-basic.test.js +444 -0
  604. package/test/form/persist-files.test.js +227 -0
  605. package/test/form/phase-banner.test.js +71 -0
  606. package/test/form/repeat.test.js +628 -0
  607. package/test/form/summary-submission-email.test.js +95 -0
  608. package/test/form/template.test.js +288 -0
  609. package/test/form/titles.test.js +204 -0
  610. package/test/helpers/component-helpers.js +74 -0
  611. package/test/utils/get-cookie.js +42 -0
  612. package/test/utils/get-form-definitions.js +18 -0
  613. package/tmp.pdf +1 -0
  614. package/tsconfig.json +28 -0
  615. package/webpack.config.js +208 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormModel.js","names":["ComponentType","ConditionsModel","ControllerPath","ControllerType","Engine","formDefinitionSchema","hasComponents","hasRepeater","add","Parser","joi","findPage","getError","getPage","createPage","validationOptions","opts","defaultServices","FormAction","merge","FormModel","engine","def","lists","sections","name","values","basePath","conditions","pages","services","controllers","pageDefMap","listDefMap","componentDefMap","pageMap","componentMap","constructor","options","result","validate","abortEarly","error","structuredClone","value","push","title","type","items","text","forEach","conditionDef","condition","makeCondition","map","pageDef","some","controller","Status","path","Map","page","list","filter","flatMap","components","component","collection","makeSchema","makeFilteredSchema","relevantPages","schema","object","required","concat","stateSchema","parser","operators","logical","Object","assign","functions","dateForComparison","timePeriod","timeUnit","Date","toISOString","displayName","expr","toConditionExpression","fn","evaluationState","ctx","toConditionContext","evaluate","context","key","defineProperty","get","from","parse","toExpression","getList","find","getFormContext","request","state","errors","query","currentPath","startPath","getStartPath","isForceAccess","relevantState","payload","getFormDataFromState","paths","data","validateFormPayload","nextPage","initialiseContext","assignEvaluationState","assignRelevantState","getNextPath","validateFormState","assignPaths","V2","keys","getContextValueFromState","includes","action","getFormParams","Validate","update","fields","field","CheckboxesField","undefined","formState","getStateFromValidForm","previousPages","relevantPage","model","stripUnknown","errorsState","details"],"sources":["../../../../../src/server/plugins/engine/models/FormModel.ts"],"sourcesContent":["import {\n ComponentType,\n ConditionsModel,\n ControllerPath,\n ControllerType,\n Engine,\n formDefinitionSchema,\n hasComponents,\n hasRepeater,\n type ComponentDef,\n type ConditionWrapper,\n type ConditionsModelData,\n type DateUnits,\n type FormDefinition,\n type List,\n type Page\n} from '@defra/forms-model'\nimport { add } from 'date-fns'\nimport { Parser, type Value } from 'expr-eval'\nimport joi from 'joi'\n\nimport { type Component } from '~/src/server/plugins/engine/components/helpers.js'\nimport {\n findPage,\n getError,\n getPage\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type ExecutableCondition } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n createPage,\n type PageControllerClass\n} from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { FormAction } from '~/src/server/routes/types.js'\nimport { merge } from '~/src/server/services/cacheService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport class FormModel {\n /** The runtime engine that should be used */\n engine?: Engine\n\n /** the entire form JSON as an object */\n def: FormDefinition\n\n lists: FormDefinition['lists']\n sections: FormDefinition['sections'] = []\n name: string\n values: FormDefinition\n basePath: string\n conditions: Partial<Record<string, ExecutableCondition>>\n pages: PageControllerClass[]\n services: Services\n\n controllers?: Record<string, typeof PageController>\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n\n constructor(\n def: typeof this.def,\n options: { basePath: string },\n services: Services = defaultServices,\n controllers?: Record<string, typeof PageController>\n ) {\n const result = formDefinitionSchema.validate(def, { abortEarly: false })\n\n if (result.error) {\n throw result.error\n }\n\n // Make a clone of the shallow copy returned\n // by joi so as not to change the source data.\n def = structuredClone(result.value)\n\n // Add default lists\n def.lists.push({\n name: '__yesNo',\n title: 'Yes/No',\n type: 'boolean',\n items: [\n {\n text: 'Yes',\n value: true\n },\n {\n text: 'No',\n value: false\n }\n ]\n })\n\n this.engine = def.engine\n this.def = def\n this.lists = def.lists\n this.sections = def.sections\n this.name = def.name ?? ''\n this.values = result.value\n this.basePath = options.basePath\n this.conditions = {}\n this.services = services\n this.controllers = controllers\n\n def.conditions.forEach((conditionDef) => {\n const condition = this.makeCondition(conditionDef)\n this.conditions[condition.name] = condition\n })\n\n this.pages = def.pages.map((pageDef) => createPage(this, pageDef))\n\n if (\n !def.pages.some(\n ({ controller }) =>\n // Check for user-provided status page (optional)\n controller === ControllerType.Status\n )\n ) {\n this.pages.push(\n createPage(this, {\n title: 'Form submitted',\n path: ControllerPath.Status,\n controller: ControllerType.Status\n })\n )\n }\n\n this.pageDefMap = new Map(def.pages.map((page) => [page.path, page]))\n this.listDefMap = new Map(def.lists.map((list) => [list.name, list]))\n this.componentDefMap = new Map(\n def.pages\n .filter(hasComponents)\n .flatMap((page) =>\n page.components.map((component) => [component.name, component])\n )\n )\n\n this.pageMap = new Map(this.pages.map((page) => [page.path, page]))\n this.componentMap = new Map(\n this.pages.flatMap((page) =>\n page.collection.components.map((component) => [\n component.name,\n component\n ])\n )\n )\n }\n\n /**\n * build the entire model schema from individual pages/sections\n */\n makeSchema() {\n return this.makeFilteredSchema(this.pages)\n }\n\n /**\n * build the entire model schema from individual pages/sections and filter out answers\n * for pages which are no longer accessible due to an answer that has been changed\n */\n makeFilteredSchema(relevantPages: PageControllerClass[]) {\n // Build the entire model schema\n // from the individual pages/sections\n let schema = joi.object<FormSubmissionState>().required()\n\n relevantPages.forEach((page) => {\n schema = schema.concat(page.collection.stateSchema)\n })\n\n return schema\n }\n\n /**\n * Instantiates a Condition based on {@link ConditionWrapper}\n * @param condition\n */\n makeCondition(condition: ConditionWrapper): ExecutableCondition {\n const parser = new Parser({\n operators: {\n logical: true\n }\n })\n\n Object.assign(parser.functions, {\n dateForComparison(timePeriod: number, timeUnit: DateUnits) {\n return add(new Date(), { [timeUnit]: timePeriod }).toISOString()\n }\n })\n\n const { name, displayName, value } = condition\n const expr = this.toConditionExpression(value, parser)\n\n const fn = (evaluationState: FormState) => {\n const ctx = this.toConditionContext(evaluationState, this.conditions)\n try {\n return expr.evaluate(ctx) as boolean\n } catch {\n return false\n }\n }\n\n return {\n name,\n displayName,\n value,\n expr,\n fn\n }\n }\n\n toConditionContext(\n evaluationState: FormState,\n conditions: Partial<Record<string, ExecutableCondition>>\n ) {\n const context = { ...evaluationState }\n\n for (const key in conditions) {\n Object.defineProperty(context, key, {\n get() {\n return conditions[key]?.fn(evaluationState)\n }\n })\n }\n\n return context as Extract<Value, Record<string, Value>>\n }\n\n toConditionExpression(value: ConditionsModelData, parser: Parser) {\n const conditions = ConditionsModel.from(value)\n return parser.parse(conditions.toExpression())\n }\n\n getList(name: string): List | undefined {\n return this.lists.find((list) => list.name === name)\n }\n\n /**\n * Form context for the current page\n */\n getFormContext(\n request: FormContextRequest,\n state: FormState,\n errors?: FormSubmissionError[]\n ): FormContext {\n const { query } = request\n\n const page = getPage(this, request)\n\n // Determine form paths\n const currentPath = page.path\n const startPath = page.getStartPath()\n\n // Preview URL direct access is allowed\n const isForceAccess = 'force' in query\n\n let context: FormContext = {\n evaluationState: {},\n relevantState: {},\n relevantPages: [],\n payload: page.getFormDataFromState(request, state),\n state,\n paths: [],\n errors,\n isForceAccess,\n data: {},\n pageDefMap: this.pageDefMap,\n listDefMap: this.listDefMap,\n componentDefMap: this.componentDefMap,\n pageMap: this.pageMap,\n componentMap: this.componentMap\n }\n\n // Validate current page\n context = validateFormPayload(request, page, context)\n\n // Find start page\n let nextPage = findPage(this, startPath)\n\n this.initialiseContext(context)\n\n // Walk form pages from start\n while (nextPage) {\n // Add page to context\n context.relevantPages.push(nextPage)\n\n this.assignEvaluationState(context, nextPage)\n\n this.assignRelevantState(context, nextPage)\n\n // Stop at current page\n if (nextPage.path === currentPath) {\n break\n }\n\n // Apply conditions to determine next page\n nextPage = findPage(this, nextPage.getNextPath(context))\n }\n\n // Validate form state\n context = validateFormState(request, page, context)\n\n // Add paths for navigation\n this.assignPaths(context)\n\n return context\n }\n\n private initialiseContext(context: FormContext) {\n // For the V2 engine, we need to initialise `evaluationState` to null\n // for all keys. This is because the current condition evaluation\n // library (eval-expr) will throw if an expression uses a key that is undefined.\n if (this.engine === Engine.V2) {\n for (const page of this.pages) {\n for (const key of page.keys) {\n context.evaluationState[key] = null\n }\n }\n }\n }\n\n private assignEvaluationState(\n context: FormContext,\n page: PageControllerClass\n ) {\n const { collection, pageDef } = page\n // Skip evaluation state for repeater pages\n\n if (!hasRepeater(pageDef)) {\n Object.assign(\n context.evaluationState,\n collection.getContextValueFromState(context.state)\n )\n }\n }\n\n private assignRelevantState(context: FormContext, page: PageControllerClass) {\n // Copy relevant state by expected keys\n for (const key of page.keys) {\n if (typeof context.state[key] !== 'undefined') {\n context.relevantState[key] = context.state[key]\n }\n }\n }\n\n private assignPaths(context: FormContext) {\n for (const { keys, path } of context.relevantPages) {\n context.paths.push(path)\n\n // Stop at page with errors\n if (\n context.errors?.some(({ name, path }) => {\n return keys.includes(name) || keys.some((key) => path.includes(key))\n })\n ) {\n break\n }\n }\n }\n}\n\n/**\n * Validate current page only\n */\nfunction validateFormPayload(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext\n): FormContext {\n const { collection } = page\n const { payload, state } = context\n\n const { action } = page.getFormParams(request)\n\n // Skip validation GET requests or other actions\n if (!request.payload || action !== FormAction.Validate) {\n return context\n }\n\n // For checkbox fields missing in the payload (i.e. unchecked),\n // explicitly set their value to undefined so that any previously\n // stored value is cleared and required field validation is enforced.\n const update = { ...request.payload }\n collection.fields.forEach((field) => {\n if (\n field.type === ComponentType.CheckboxesField &&\n !(field.name in update)\n ) {\n update[field.name] = undefined\n }\n })\n\n const { value, errors } = collection.validate({\n ...payload,\n ...update\n })\n\n // Add sanitised payload (ready to save)\n const formState = page.getStateFromValidForm(request, state, value)\n\n return {\n ...context,\n payload: merge(payload, value),\n state: merge(state, formState),\n errors\n }\n}\n\n/**\n * Validate entire form state\n */\nfunction validateFormState(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext\n): FormContext {\n const { errors = [], relevantPages, relevantState } = context\n\n // Exclude current page\n const previousPages = relevantPages.filter(\n (relevantPage) => relevantPage !== page\n )\n\n // Validate relevant state\n const { error } = page.model\n .makeFilteredSchema(previousPages)\n .validate(relevantState, { ...opts, stripUnknown: true })\n\n // Add relevant state errors\n if (error) {\n const errorsState = error.details.map(getError)\n return { ...context, errors: errors.concat(errorsState) }\n }\n\n return context\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=RepeatingSummaryViewModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RepeatingSummaryViewModel.js","names":[],"sources":["../../../../../src/server/plugins/engine/models/RepeatingSummaryViewModel.ts"],"sourcesContent":[""],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=Section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Section.js","names":[],"sources":["../../../../../src/server/plugins/engine/models/Section.ts"],"sourcesContent":[""],"mappings":"","ignoreList":[]}
@@ -0,0 +1,183 @@
1
+ import { getAnswer } from "../components/helpers.js";
2
+ import { evaluateTemplate, getError, getPageHref } from "../helpers.js";
3
+ import { RepeatPageController } from "../pageControllers/RepeatPageController.js";
4
+ import { validationOptions as opts } from "../pageControllers/validationOptions.js";
5
+ export class SummaryViewModel {
6
+ /**
7
+ * Responsible for parsing state values to the govuk-frontend summary list template
8
+ */
9
+
10
+ page;
11
+ pageTitle;
12
+ declaration;
13
+ details;
14
+ checkAnswers;
15
+ context;
16
+ name;
17
+ backLink;
18
+ feedbackLink;
19
+ phaseTag;
20
+ errors;
21
+ serviceUrl;
22
+ hasMissingNotificationEmail;
23
+ constructor(request, page, context) {
24
+ const {
25
+ model
26
+ } = page;
27
+ const {
28
+ basePath,
29
+ def,
30
+ sections
31
+ } = model;
32
+ const {
33
+ isForceAccess
34
+ } = context;
35
+ this.page = page;
36
+ this.pageTitle = page.title;
37
+ this.serviceUrl = `/${basePath}`;
38
+ this.name = def.name;
39
+ this.declaration = def.declaration;
40
+ this.context = context;
41
+ const result = model.makeFilteredSchema(this.context.relevantPages).validate(this.context.relevantState, {
42
+ ...opts,
43
+ stripUnknown: true
44
+ });
45
+
46
+ // Format errors
47
+ this.errors = result.error?.details.map(getError);
48
+ this.details = this.summaryDetails(request, sections);
49
+
50
+ // Format check answers
51
+ this.checkAnswers = this.details.map(detail => {
52
+ const {
53
+ title
54
+ } = detail;
55
+ const rows = detail.items.map(item => {
56
+ const items = [];
57
+
58
+ // Remove summary list actions from previews
59
+ if (!isForceAccess) {
60
+ items.push({
61
+ href: item.href,
62
+ text: 'Change',
63
+ classes: 'govuk-link--no-visited-state',
64
+ visuallyHiddenText: item.label
65
+ });
66
+ }
67
+ return {
68
+ key: {
69
+ text: evaluateTemplate(item.title, context)
70
+ },
71
+ value: {
72
+ classes: 'app-prose-scope',
73
+ html: item.value || 'Not supplied'
74
+ },
75
+ actions: {
76
+ items
77
+ }
78
+ };
79
+ });
80
+ return {
81
+ title: title ? {
82
+ text: title
83
+ } : undefined,
84
+ summaryList: {
85
+ rows
86
+ }
87
+ };
88
+ });
89
+ }
90
+ summaryDetails(request, sections) {
91
+ const {
92
+ context,
93
+ errors
94
+ } = this;
95
+ const {
96
+ relevantPages,
97
+ state
98
+ } = context;
99
+ const details = [];
100
+ [undefined, ...sections].forEach(section => {
101
+ const items = [];
102
+ const sectionPages = relevantPages.filter(page => page.section === section);
103
+ sectionPages.forEach(page => {
104
+ const {
105
+ collection,
106
+ path
107
+ } = page;
108
+ if (page instanceof RepeatPageController) {
109
+ items.push(ItemRepeat(page, state, {
110
+ path: page.getSummaryPath(request),
111
+ errors
112
+ }));
113
+ } else {
114
+ for (const field of collection.fields) {
115
+ items.push(ItemField(page, state, field, {
116
+ path,
117
+ errors
118
+ }));
119
+ }
120
+ }
121
+ });
122
+ if (items.length) {
123
+ details.push({
124
+ name: section?.name,
125
+ title: section?.title,
126
+ items
127
+ });
128
+ }
129
+ });
130
+ return details;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Creates a repeater detail item
136
+ * @see {@link DetailItemField}
137
+ */
138
+ function ItemRepeat(page, state, options) {
139
+ const {
140
+ collection,
141
+ repeat
142
+ } = page;
143
+ const {
144
+ name,
145
+ title
146
+ } = repeat.options;
147
+ const values = page.getListFromState(state);
148
+ const unit = values.length === 1 ? title : `${title}s`;
149
+ return {
150
+ name,
151
+ label: title,
152
+ title: values.length ? `${unit} added` : unit,
153
+ value: values.length ? `You added ${values.length} ${unit}` : '',
154
+ href: getPageHref(page, options.path, {
155
+ returnUrl: getPageHref(page, page.getSummaryPath())
156
+ }),
157
+ state,
158
+ page,
159
+ // Repeater field detail items
160
+ subItems: values.map(repeatState => collection.fields.map(field => ItemField(page, repeatState, field, options)))
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Creates a form field detail item
166
+ * @see {@link DetailItemField}
167
+ */
168
+ function ItemField(page, state, field, options) {
169
+ return {
170
+ name: field.name,
171
+ label: field.title,
172
+ title: field.title,
173
+ error: field.getError(options.errors),
174
+ value: getAnswer(field, state),
175
+ href: getPageHref(page, options.path, {
176
+ returnUrl: getPageHref(page, page.getSummaryPath())
177
+ }),
178
+ state,
179
+ page,
180
+ field
181
+ };
182
+ }
183
+ //# sourceMappingURL=SummaryViewModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SummaryViewModel.js","names":["getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","constructor","request","model","basePath","def","sections","isForceAccess","title","result","makeFilteredSchema","relevantPages","validate","relevantState","stripUnknown","error","map","summaryDetails","detail","rows","items","item","push","href","text","classes","visuallyHiddenText","label","key","value","html","actions","undefined","summaryList","state","forEach","section","sectionPages","filter","collection","path","ItemRepeat","getSummaryPath","field","fields","ItemField","length","options","repeat","values","getListFromState","unit","returnUrl","subItems","repeatState"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import { type Section } from '@defra/forms-model'\n\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type BackLink } from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.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 CheckAnswers,\n type FormContext,\n type FormContextRequest,\n type FormState,\n type FormSubmissionError,\n type SummaryListAction,\n type SummaryListRow\n} from '~/src/server/plugins/engine/types.js'\n\nexport class SummaryViewModel {\n /**\n * Responsible for parsing state values to the govuk-frontend summary list template\n */\n\n page: PageControllerClass\n pageTitle: string\n declaration?: string\n details: Detail[]\n checkAnswers: CheckAnswers[]\n context: FormContext\n name: string | undefined\n backLink?: BackLink\n feedbackLink?: string\n phaseTag?: string\n errors?: FormSubmissionError[]\n serviceUrl: string\n hasMissingNotificationEmail?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n this.page = page\n this.pageTitle = page.title\n this.serviceUrl = `/${basePath}`\n this.name = def.name\n this.declaration = def.declaration\n this.context = context\n\n const result = model\n .makeFilteredSchema(this.context.relevantPages)\n .validate(this.context.relevantState, { ...opts, stripUnknown: true })\n\n // Format errors\n this.errors = result.error?.details.map(getError)\n this.details = this.summaryDetails(request, sections)\n\n // Format check answers\n this.checkAnswers = this.details.map((detail): CheckAnswers => {\n const { title } = detail\n\n const rows = detail.items.map((item): SummaryListRow => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: item.href,\n text: 'Change',\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: item.label\n })\n }\n\n return {\n key: {\n text: evaluateTemplate(item.title, context)\n },\n value: {\n classes: 'app-prose-scope',\n html: item.value || 'Not supplied'\n },\n actions: {\n items\n }\n }\n })\n\n return {\n title: title ? { text: title } : undefined,\n summaryList: { rows }\n }\n })\n }\n\n private summaryDetails(request: FormContextRequest, sections: Section[]) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[undefined, ...sections].forEach((section) => {\n const items: DetailItem[] = []\n\n const sectionPages = relevantPages.filter(\n (page) => page.section === section\n )\n\n sectionPages.forEach((page) => {\n const { collection, path } = page\n\n if (page instanceof RepeatPageController) {\n items.push(\n ItemRepeat(page, state, {\n path: page.getSummaryPath(request),\n errors\n })\n )\n } else {\n for (const field of collection.fields) {\n items.push(ItemField(page, state, field, { path, errors }))\n }\n }\n })\n\n if (items.length) {\n details.push({\n name: section?.name,\n title: section?.title,\n items\n })\n }\n })\n\n return details\n }\n}\n\n/**\n * Creates a repeater detail item\n * @see {@link DetailItemField}\n */\nfunction ItemRepeat(\n page: RepeatPageController,\n state: FormState,\n options: {\n path: string\n errors?: FormSubmissionError[]\n }\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name, title } = repeat.options\n\n const values = page.getListFromState(state)\n const unit = values.length === 1 ? title : `${title}s`\n\n return {\n name,\n label: title,\n title: values.length ? `${unit} added` : unit,\n value: values.length ? `You added ${values.length} ${unit}` : '',\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n\n // Repeater field detail items\n subItems: values.map((repeatState) =>\n collection.fields.map((field) =>\n ItemField(page, repeatState, field, options)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nfunction ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n }\n): DetailItemField {\n return {\n name: field.name,\n label: field.title,\n title: field.title,\n error: field.getError(options.errors),\n value: getAnswer(field, state),\n href: getPageHref(page, options.path, {\n returnUrl: getPageHref(page, page.getSummaryPath())\n }),\n state,\n page,\n field\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ export { FormModel } from "./FormModel.js";
2
+ export { SummaryViewModel } from "./SummaryViewModel.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["FormModel","SummaryViewModel"],"sources":["../../../../../src/server/plugins/engine/models/index.ts"],"sourcesContent":["export { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nexport { SummaryViewModel } from '~/src/server/plugins/engine/models/SummaryViewModel.js'\n"],"mappings":"AAAA,SAASA,SAAS;AAClB,SAASC,gBAAgB","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/models/types.ts"],"sourcesContent":["import {\n type ConditionWrapper,\n type FormComponentsDef,\n type Section\n} from '@defra/forms-model'\nimport { type Expression } from 'expr-eval'\n\nimport {\n type Field,\n type getAnswer\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport {\n type FormState,\n type FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nexport type ExecutableCondition = ConditionWrapper & {\n expr: Expression\n fn: (evaluationState: FormState) => boolean\n}\n\n/**\n * Used to render a row on a Summary List (check your answers)\n */\nexport interface DetailItemBase {\n /**\n * Name of the component defined in the JSON\n * @see {@link FormComponentsDef.name}\n */\n name: string\n\n /**\n * Field label, used for change link visually hidden text\n * @see {@link FormComponentsDef.title}\n */\n label: string\n\n /**\n * Field change link\n */\n href: string\n\n /**\n * Form submission state (or repeat state for sub items)\n */\n state: FormState\n\n /**\n * Field submission state error, used to flag unanswered questions\n * Shown as 'Complete all unanswered questions before submitting the form'\n */\n error?: FormSubmissionError\n}\n\nexport interface DetailItemField extends DetailItemBase {\n /**\n * Field page controller instance\n */\n page: Exclude<PageControllerClass, RepeatPageController>\n\n /**\n * Check answers summary list key\n * For example, 'Date of birth'\n */\n title: string\n\n /**\n * Check answers summary list value, formatted by {@link getAnswer}\n * For example, date fields formatted as '25 December 2022'\n */\n value: string\n\n /**\n * Field component instance\n */\n field: Field\n}\n\nexport interface DetailItemRepeat extends DetailItemBase {\n /**\n * Repeat page controller instance\n */\n page: RepeatPageController\n\n /**\n * Check answers summary list key\n * For example, 'Pizza' or 'Pizza added'\n */\n title: string\n\n /**\n * Check answers summary list value\n * For example, 'You added 2 Pizzas'\n */\n value: string\n\n /**\n * Repeater field detail items\n */\n subItems: DetailItemField[][]\n}\n\nexport type DetailItem = DetailItemField | DetailItemRepeat\n\n/**\n * Used to render a row on a Summary List (check your answers)\n */\nexport interface Detail {\n name?: Section['name']\n title?: Section['title']\n items: DetailItem[]\n}\n"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,44 @@
1
+ import { addDays, format as dateFormat } from 'date-fns';
2
+ import { config } from "../../../../../config/index.js";
3
+ import { escapeMarkdown, getAnswer } from "../../components/helpers.js";
4
+ const designerUrl = config.get('designerUrl');
5
+ export function format(items, model, submitResponse, formStatus) {
6
+ const {
7
+ files
8
+ } = submitResponse.result;
9
+ const formName = escapeMarkdown(model.name);
10
+
11
+ /**
12
+ * @todo Refactor this below but the code to
13
+ * generate the question and answers works for now
14
+ */
15
+ const now = new Date();
16
+ const formattedNow = `${dateFormat(now, 'h:mmaaa')} on ${dateFormat(now, 'd MMMM yyyy')}`;
17
+ const fileExpiryDate = addDays(now, 90);
18
+ const formattedExpiryDate = `${dateFormat(fileExpiryDate, 'h:mmaaa')} on ${dateFormat(fileExpiryDate, 'eeee d MMMM yyyy')}`;
19
+ const lines = [];
20
+ lines.push(`^ For security reasons, the links in this email expire at ${escapeMarkdown(formattedExpiryDate)}\n`);
21
+ if (formStatus.isPreview) {
22
+ lines.push(`This is a test of the ${formName} ${formStatus.state} form.\n`);
23
+ }
24
+ lines.push(`Form submitted at ${escapeMarkdown(formattedNow)}.\n`);
25
+ lines.push('---\n');
26
+ items.forEach(item => {
27
+ const label = escapeMarkdown(item.label);
28
+ lines.push(`## ${label}\n`);
29
+ if ('subItems' in item) {
30
+ const filename = escapeMarkdown(`Download ${label} (CSV)`);
31
+ const fileId = files.repeaters[item.name];
32
+ lines.push(`[${filename}](${designerUrl}/file-download/${fileId})\n`);
33
+ } else {
34
+ lines.push(getAnswer(item.field, item.state, {
35
+ format: 'email'
36
+ }));
37
+ }
38
+ lines.push('---\n');
39
+ });
40
+ const filename = escapeMarkdown('Download main form (CSV)');
41
+ lines.push(`[${filename}](${designerUrl}/file-download/${files.main})\n`);
42
+ return lines.join('\n');
43
+ }
44
+ //# sourceMappingURL=v1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v1.js","names":["addDays","format","dateFormat","config","escapeMarkdown","getAnswer","designerUrl","get","items","model","submitResponse","formStatus","files","result","formName","name","now","Date","formattedNow","fileExpiryDate","formattedExpiryDate","lines","push","isPreview","state","forEach","item","label","filename","fileId","repeaters","field","main","join"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/human/v1.ts"],"sourcesContent":["import { type SubmitResponsePayload } from '@defra/forms-model'\nimport { addDays, format as dateFormat } from 'date-fns'\n\nimport { config } from '~/src/config/index.js'\nimport {\n escapeMarkdown,\n getAnswer\n} from '~/src/server/plugins/engine/components/helpers.js'\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>\n) {\n const { files } = submitResponse.result\n\n const formName = escapeMarkdown(model.name)\n\n /**\n * @todo Refactor this below but the code to\n * generate the question and answers works for now\n */\n const now = new Date()\n const formattedNow = `${dateFormat(now, 'h:mmaaa')} on ${dateFormat(now, 'd MMMM yyyy')}`\n\n const fileExpiryDate = addDays(now, 90)\n const formattedExpiryDate = `${dateFormat(fileExpiryDate, 'h:mmaaa')} on ${dateFormat(fileExpiryDate, 'eeee d MMMM yyyy')}`\n\n const lines: string[] = []\n\n lines.push(\n `^ For security reasons, the links in this email expire at ${escapeMarkdown(formattedExpiryDate)}\\n`\n )\n\n if (formStatus.isPreview) {\n lines.push(`This is a test of the ${formName} ${formStatus.state} form.\\n`)\n }\n\n lines.push(`Form submitted at ${escapeMarkdown(formattedNow)}.\\n`)\n lines.push('---\\n')\n\n items.forEach((item) => {\n const label = escapeMarkdown(item.label)\n\n lines.push(`## ${label}\\n`)\n\n if ('subItems' in item) {\n const filename = escapeMarkdown(`Download ${label} (CSV)`)\n const fileId = files.repeaters[item.name]\n\n lines.push(`[${filename}](${designerUrl}/file-download/${fileId})\\n`)\n } else {\n lines.push(\n getAnswer(item.field, item.state, {\n format: 'email'\n })\n )\n }\n\n lines.push('---\\n')\n })\n\n const filename = escapeMarkdown('Download main form (CSV)')\n lines.push(`[${filename}](${designerUrl}/file-download/${files.main})\\n`)\n\n return lines.join('\\n')\n}\n"],"mappings":"AACA,SAASA,OAAO,EAAEC,MAAM,IAAIC,UAAU,QAAQ,UAAU;AAExD,SAASC,MAAM;AACf,SACEC,cAAc,EACdC,SAAS;AAMX,MAAMC,WAAW,GAAGH,MAAM,CAACI,GAAG,CAAC,aAAa,CAAC;AAE7C,OAAO,SAASN,MAAMA,CACpBO,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9C;EACA,MAAM;IAAEC;EAAM,CAAC,GAAGF,cAAc,CAACG,MAAM;EAEvC,MAAMC,QAAQ,GAAGV,cAAc,CAACK,KAAK,CAACM,IAAI,CAAC;;EAE3C;AACF;AACA;AACA;EACE,MAAMC,GAAG,GAAG,IAAIC,IAAI,CAAC,CAAC;EACtB,MAAMC,YAAY,GAAG,GAAGhB,UAAU,CAACc,GAAG,EAAE,SAAS,CAAC,OAAOd,UAAU,CAACc,GAAG,EAAE,aAAa,CAAC,EAAE;EAEzF,MAAMG,cAAc,GAAGnB,OAAO,CAACgB,GAAG,EAAE,EAAE,CAAC;EACvC,MAAMI,mBAAmB,GAAG,GAAGlB,UAAU,CAACiB,cAAc,EAAE,SAAS,CAAC,OAAOjB,UAAU,CAACiB,cAAc,EAAE,kBAAkB,CAAC,EAAE;EAE3H,MAAME,KAAe,GAAG,EAAE;EAE1BA,KAAK,CAACC,IAAI,CACR,6DAA6DlB,cAAc,CAACgB,mBAAmB,CAAC,IAClG,CAAC;EAED,IAAIT,UAAU,CAACY,SAAS,EAAE;IACxBF,KAAK,CAACC,IAAI,CAAC,yBAAyBR,QAAQ,IAAIH,UAAU,CAACa,KAAK,UAAU,CAAC;EAC7E;EAEAH,KAAK,CAACC,IAAI,CAAC,qBAAqBlB,cAAc,CAACc,YAAY,CAAC,KAAK,CAAC;EAClEG,KAAK,CAACC,IAAI,CAAC,OAAO,CAAC;EAEnBd,KAAK,CAACiB,OAAO,CAAEC,IAAI,IAAK;IACtB,MAAMC,KAAK,GAAGvB,cAAc,CAACsB,IAAI,CAACC,KAAK,CAAC;IAExCN,KAAK,CAACC,IAAI,CAAC,MAAMK,KAAK,IAAI,CAAC;IAE3B,IAAI,UAAU,IAAID,IAAI,EAAE;MACtB,MAAME,QAAQ,GAAGxB,cAAc,CAAC,YAAYuB,KAAK,QAAQ,CAAC;MAC1D,MAAME,MAAM,GAAGjB,KAAK,CAACkB,SAAS,CAACJ,IAAI,CAACX,IAAI,CAAC;MAEzCM,KAAK,CAACC,IAAI,CAAC,IAAIM,QAAQ,KAAKtB,WAAW,kBAAkBuB,MAAM,KAAK,CAAC;IACvE,CAAC,MAAM;MACLR,KAAK,CAACC,IAAI,CACRjB,SAAS,CAACqB,IAAI,CAACK,KAAK,EAAEL,IAAI,CAACF,KAAK,EAAE;QAChCvB,MAAM,EAAE;MACV,CAAC,CACH,CAAC;IACH;IAEAoB,KAAK,CAACC,IAAI,CAAC,OAAO,CAAC;EACrB,CAAC,CAAC;EAEF,MAAMM,QAAQ,GAAGxB,cAAc,CAAC,0BAA0B,CAAC;EAC3DiB,KAAK,CAACC,IAAI,CAAC,IAAIM,QAAQ,KAAKtB,WAAW,kBAAkBM,KAAK,CAACoB,IAAI,KAAK,CAAC;EAEzE,OAAOX,KAAK,CAACY,IAAI,CAAC,IAAI,CAAC;AACzB","ignoreList":[]}
@@ -0,0 +1,24 @@
1
+ import { format as formatHumanV1 } from "./human/v1.js";
2
+ import { format as formatMachineV1 } from "./machine/v1.js";
3
+ import { format as formatMachineV2 } from "./machine/v2.js";
4
+ const formatters = {
5
+ human: {
6
+ '1': formatHumanV1
7
+ },
8
+ machine: {
9
+ '1': formatMachineV1,
10
+ '2': formatMachineV2
11
+ }
12
+ };
13
+ export function getFormatter(audience, version) {
14
+ const versions = formatters[audience];
15
+ if (!versions) {
16
+ throw new Error('Unknown audience');
17
+ }
18
+ const formatter = versions[version];
19
+ if (!formatter) {
20
+ throw new Error('Unknown version');
21
+ }
22
+ return formatter;
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["format","formatHumanV1","formatMachineV1","formatMachineV2","formatters","human","machine","getFormatter","audience","version","versions","Error","formatter"],"sources":["../../../../../src/server/plugins/engine/outputFormatters/index.ts"],"sourcesContent":["import { type SubmitResponsePayload } from '@defra/forms-model'\n\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { format as formatHumanV1 } from '~/src/server/plugins/engine/outputFormatters/human/v1.js'\nimport { format as formatMachineV1 } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'\nimport { format as formatMachineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\n\ntype Formatter = (\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>\n) => string\n\nconst formatters: Record<\n string,\n Record<string, Formatter | undefined> | undefined\n> = {\n human: {\n '1': formatHumanV1\n },\n machine: {\n '1': formatMachineV1,\n '2': formatMachineV2\n }\n}\n\nexport function getFormatter(audience: string, version: string) {\n const versions = formatters[audience]\n\n if (!versions) {\n throw new Error('Unknown audience')\n }\n\n const formatter = versions[version]\n\n if (!formatter) {\n throw new Error('Unknown version')\n }\n\n return formatter\n}\n"],"mappings":"AAKA,SAASA,MAAM,IAAIC,aAAa;AAChC,SAASD,MAAM,IAAIE,eAAe;AAClC,SAASF,MAAM,IAAIG,eAAe;AASlC,MAAMC,UAGL,GAAG;EACFC,KAAK,EAAE;IACL,GAAG,EAAEJ;EACP,CAAC;EACDK,OAAO,EAAE;IACP,GAAG,EAAEJ,eAAe;IACpB,GAAG,EAAEC;EACP;AACF,CAAC;AAED,OAAO,SAASI,YAAYA,CAACC,QAAgB,EAAEC,OAAe,EAAE;EAC9D,MAAMC,QAAQ,GAAGN,UAAU,CAACI,QAAQ,CAAC;EAErC,IAAI,CAACE,QAAQ,EAAE;IACb,MAAM,IAAIC,KAAK,CAAC,kBAAkB,CAAC;EACrC;EAEA,MAAMC,SAAS,GAAGF,QAAQ,CAACD,OAAO,CAAC;EAEnC,IAAI,CAACG,SAAS,EAAE;IACd,MAAM,IAAID,KAAK,CAAC,iBAAiB,CAAC;EACpC;EAEA,OAAOC,SAAS;AAClB","ignoreList":[]}
@@ -0,0 +1,104 @@
1
+ import { config } from "../../../../../config/index.js";
2
+ import { getAnswer } from "../../components/helpers.js";
3
+ import { FileUploadField } from "../../components/index.js";
4
+ const designerUrl = config.get('designerUrl');
5
+ export function format(items, model, _submitResponse, _formStatus) {
6
+ const now = new Date();
7
+ const categorisedData = categoriseData(items);
8
+ const data = {
9
+ meta: {
10
+ schemaVersion: '1',
11
+ timestamp: now.toISOString(),
12
+ definition: model.def
13
+ },
14
+ data: categorisedData
15
+ };
16
+ const body = JSON.stringify(data);
17
+ return body;
18
+ }
19
+
20
+ /**
21
+ * Categories the form submission data into the "main" body and "repeaters".
22
+ *
23
+ * {
24
+ * main: {
25
+ * componentName: 'componentValue',
26
+ * },
27
+ * repeaters: {
28
+ * repeaterName: [
29
+ * {
30
+ * componentName: 'componentValue'
31
+ * }
32
+ * ]
33
+ * },
34
+ * files: {
35
+ * fileComponentName: [
36
+ * {
37
+ * fileId: '123-456-789',
38
+ * link: 'https://forms-designer/file-download/123-456-789'
39
+ * }
40
+ * ]
41
+ * }
42
+ * }
43
+ */
44
+ function categoriseData(items) {
45
+ const output = {
46
+ main: {},
47
+ repeaters: {},
48
+ files: {}
49
+ };
50
+ items.forEach(item => {
51
+ if ('subItems' in item) {
52
+ output.repeaters[item.name] = extractRepeaters(item);
53
+ } else if (isFileUploadFieldItem(item)) {
54
+ output.files[item.name] = extractFileUploads(item);
55
+ } else {
56
+ output.main[item.name] = getAnswer(item.field, item.state, {
57
+ format: 'data'
58
+ });
59
+ }
60
+ });
61
+ return output;
62
+ }
63
+
64
+ /**
65
+ * Returns the "repeaters" section of the response body
66
+ * @param item - the repeater item
67
+ * @returns the repeater item
68
+ */
69
+ function extractRepeaters(item) {
70
+ const repeaters = [];
71
+ item.subItems.forEach(inputRepeaterItem => {
72
+ const outputRepeaterItem = {};
73
+ inputRepeaterItem.forEach(repeaterComponent => {
74
+ outputRepeaterItem[repeaterComponent.name] = getAnswer(repeaterComponent.field, repeaterComponent.state, {
75
+ format: 'data'
76
+ });
77
+ });
78
+ repeaters.push(outputRepeaterItem);
79
+ });
80
+ return repeaters;
81
+ }
82
+
83
+ /**
84
+ * Returns the "files" section of the response body
85
+ * @param item - the file upload item in the form
86
+ * @returns the file upload data
87
+ */
88
+ function extractFileUploads(item) {
89
+ const fileUploadState = item.field.getContextValueFromState(item.state) ?? [];
90
+ return fileUploadState.map(fileId => {
91
+ return {
92
+ fileId,
93
+ userDownloadLink: `${designerUrl}/file-download/${fileId}`
94
+ };
95
+ });
96
+ }
97
+ function isFileUploadFieldItem(item) {
98
+ return item.field instanceof FileUploadField;
99
+ }
100
+
101
+ /**
102
+ * A detail item specifically for files
103
+ */
104
+ //# sourceMappingURL=v1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v1.js","names":["config","getAnswer","FileUploadField","designerUrl","get","format","items","model","_submitResponse","_formStatus","now","Date","categorisedData","categoriseData","data","meta","schemaVersion","timestamp","toISOString","definition","def","body","JSON","stringify","output","main","repeaters","files","forEach","item","name","extractRepeaters","isFileUploadFieldItem","extractFileUploads","field","state","subItems","inputRepeaterItem","outputRepeaterItem","repeaterComponent","push","fileUploadState","getContextValueFromState","map","fileId","userDownloadLink"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/machine/v1.ts"],"sourcesContent":["import { type SubmitResponsePayload } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { getAnswer } from '~/src/server/plugins/engine/components/helpers.js'\nimport { FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n items: DetailItem[],\n model: FormModel,\n _submitResponse: SubmitResponsePayload,\n _formStatus: ReturnType<typeof checkFormStatus>\n) {\n const now = new Date()\n\n const categorisedData = categoriseData(items)\n\n const data = {\n meta: {\n schemaVersion: '1',\n timestamp: now.toISOString(),\n definition: model.def\n },\n data: categorisedData\n }\n\n const body = JSON.stringify(data)\n\n return body\n}\n\n/**\n * Categories the form submission data into the \"main\" body and \"repeaters\".\n *\n * {\n * main: {\n * componentName: 'componentValue',\n * },\n * repeaters: {\n * repeaterName: [\n * {\n * componentName: 'componentValue'\n * }\n * ]\n * },\n * files: {\n * fileComponentName: [\n * {\n * fileId: '123-456-789',\n * link: 'https://forms-designer/file-download/123-456-789'\n * }\n * ]\n * }\n * }\n */\nfunction categoriseData(items: DetailItem[]) {\n const output: {\n main: Record<string, string>\n repeaters: Record<string, Record<string, string>[]>\n files: Record<string, Record<string, string>[]>\n } = { main: {}, repeaters: {}, files: {} }\n\n items.forEach((item) => {\n if ('subItems' in item) {\n output.repeaters[item.name] = extractRepeaters(item)\n } else if (isFileUploadFieldItem(item)) {\n output.files[item.name] = extractFileUploads(item)\n } else {\n output.main[item.name] = getAnswer(item.field, item.state, {\n format: 'data'\n })\n }\n })\n\n return output\n}\n\n/**\n * Returns the \"repeaters\" section of the response body\n * @param item - the repeater item\n * @returns the repeater item\n */\nfunction extractRepeaters(item: DetailItemRepeat) {\n const repeaters: Record<string, string>[] = []\n\n item.subItems.forEach((inputRepeaterItem) => {\n const outputRepeaterItem: Record<string, string> = {}\n\n inputRepeaterItem.forEach((repeaterComponent) => {\n outputRepeaterItem[repeaterComponent.name] = getAnswer(\n repeaterComponent.field,\n repeaterComponent.state,\n {\n format: 'data'\n }\n )\n })\n\n repeaters.push(outputRepeaterItem)\n })\n\n return repeaters\n}\n\n/**\n * Returns the \"files\" section of the response body\n * @param item - the file upload item in the form\n * @returns the file upload data\n */\nfunction extractFileUploads(item: FileUploadFieldDetailitem) {\n const fileUploadState = item.field.getContextValueFromState(item.state) ?? []\n\n return fileUploadState.map((fileId) => {\n return {\n fileId,\n userDownloadLink: `${designerUrl}/file-download/${fileId}`\n }\n })\n}\n\nfunction isFileUploadFieldItem(\n item: DetailItemField\n): item is FileUploadFieldDetailitem {\n return item.field instanceof FileUploadField\n}\n\n/**\n * A detail item specifically for files\n */\ntype FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,110 @@
1
+ import { config } from "../../../../../config/index.js";
2
+ import { FileUploadField } from "../../components/index.js";
3
+ const designerUrl = config.get('designerUrl');
4
+ export function format(items, model, _submitResponse, _formStatus) {
5
+ const now = new Date();
6
+ const categorisedData = categoriseData(items);
7
+ const data = {
8
+ meta: {
9
+ schemaVersion: '2',
10
+ timestamp: now.toISOString(),
11
+ definition: model.def
12
+ },
13
+ data: categorisedData
14
+ };
15
+ const body = JSON.stringify(data);
16
+ return body;
17
+ }
18
+
19
+ /**
20
+ * Categories the form submission data into the "main" body and "repeaters".
21
+ *
22
+ * {
23
+ * main: {
24
+ * componentName: 'componentValue',
25
+ * },
26
+ * repeaters: {
27
+ * repeaterName: [
28
+ * {
29
+ * textComponentName: 'componentValue'
30
+ * },
31
+ * {
32
+ * richComponentName: { foo: 'bar', 'baz': true }
33
+ * }
34
+ * ]
35
+ * },
36
+ * files: {
37
+ * fileComponentName: [
38
+ * {
39
+ * fileId: '123-456-789',
40
+ * link: 'https://forms-designer/file-download/123-456-789'
41
+ * }
42
+ * ]
43
+ * }
44
+ * }
45
+ */
46
+ function categoriseData(items) {
47
+ const output = {
48
+ main: {},
49
+ repeaters: {},
50
+ files: {}
51
+ };
52
+ items.forEach(item => {
53
+ const {
54
+ name,
55
+ state
56
+ } = item;
57
+ if ('subItems' in item) {
58
+ output.repeaters[name] = extractRepeaters(item);
59
+ } else if (isFileUploadFieldItem(item)) {
60
+ output.files[name] = extractFileUploads(item);
61
+ } else {
62
+ output.main[name] = item.field.getFormValueFromState(state);
63
+ }
64
+ });
65
+ return output;
66
+ }
67
+
68
+ /**
69
+ * Returns the "repeaters" section of the response body
70
+ * @param item - the repeater item
71
+ * @returns the repeater item
72
+ */
73
+ function extractRepeaters(item) {
74
+ const repeaters = [];
75
+ item.subItems.forEach(inputRepeaterItem => {
76
+ const outputRepeaterItem = {};
77
+ inputRepeaterItem.forEach(repeaterComponent => {
78
+ const {
79
+ field,
80
+ state
81
+ } = repeaterComponent;
82
+ outputRepeaterItem[repeaterComponent.name] = field.getFormValueFromState(state);
83
+ });
84
+ repeaters.push(outputRepeaterItem);
85
+ });
86
+ return repeaters;
87
+ }
88
+
89
+ /**
90
+ * Returns the "files" section of the response body
91
+ * @param item - the file upload item in the form
92
+ * @returns the file upload data
93
+ */
94
+ function extractFileUploads(item) {
95
+ const fileUploadState = item.field.getContextValueFromState(item.state) ?? [];
96
+ return fileUploadState.map(fileId => {
97
+ return {
98
+ fileId,
99
+ userDownloadLink: `${designerUrl}/file-download/${fileId}`
100
+ };
101
+ });
102
+ }
103
+ function isFileUploadFieldItem(item) {
104
+ return item.field instanceof FileUploadField;
105
+ }
106
+
107
+ /**
108
+ * A detail item specifically for files
109
+ */
110
+ //# sourceMappingURL=v2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.js","names":["config","FileUploadField","designerUrl","get","format","items","model","_submitResponse","_formStatus","now","Date","categorisedData","categoriseData","data","meta","schemaVersion","timestamp","toISOString","definition","def","body","JSON","stringify","output","main","repeaters","files","forEach","item","name","state","extractRepeaters","isFileUploadFieldItem","extractFileUploads","field","getFormValueFromState","subItems","inputRepeaterItem","outputRepeaterItem","repeaterComponent","push","fileUploadState","getContextValueFromState","map","fileId","userDownloadLink"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/machine/v2.ts"],"sourcesContent":["import { type SubmitResponsePayload } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { type DatePartsState } from '~/src/server/plugins/engine/components/DatePartsField.js'\nimport { type MonthYearState } from '~/src/server/plugins/engine/components/MonthYearField.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport {\n type FormPayload,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n items: DetailItem[],\n model: FormModel,\n _submitResponse: SubmitResponsePayload,\n _formStatus: ReturnType<typeof checkFormStatus>\n) {\n const now = new Date()\n\n const categorisedData = categoriseData(items)\n\n const data = {\n meta: {\n schemaVersion: '2',\n timestamp: now.toISOString(),\n definition: model.def\n },\n data: categorisedData\n }\n\n const body = JSON.stringify(data)\n\n return body\n}\n\n/**\n * Categories the form submission data into the \"main\" body and \"repeaters\".\n *\n * {\n * main: {\n * componentName: 'componentValue',\n * },\n * repeaters: {\n * repeaterName: [\n * {\n * textComponentName: 'componentValue'\n * },\n * {\n * richComponentName: { foo: 'bar', 'baz': true }\n * }\n * ]\n * },\n * files: {\n * fileComponentName: [\n * {\n * fileId: '123-456-789',\n * link: 'https://forms-designer/file-download/123-456-789'\n * }\n * ]\n * }\n * }\n */\nfunction categoriseData(items: DetailItem[]) {\n const output: {\n main: Record<string, RichFormValue>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, Record<string, string>[]>\n } = { main: {}, repeaters: {}, files: {} }\n\n items.forEach((item) => {\n const { name, state } = item\n\n if ('subItems' in item) {\n output.repeaters[name] = extractRepeaters(item)\n } else if (isFileUploadFieldItem(item)) {\n output.files[name] = extractFileUploads(item)\n } else {\n output.main[name] = item.field.getFormValueFromState(state)\n }\n })\n\n return output\n}\n\n/**\n * Returns the \"repeaters\" section of the response body\n * @param item - the repeater item\n * @returns the repeater item\n */\nfunction extractRepeaters(item: DetailItemRepeat) {\n const repeaters: Record<string, RichFormValue>[] = []\n\n item.subItems.forEach((inputRepeaterItem) => {\n const outputRepeaterItem: Record<string, RichFormValue> = {}\n\n inputRepeaterItem.forEach((repeaterComponent) => {\n const { field, state } = repeaterComponent\n\n outputRepeaterItem[repeaterComponent.name] =\n field.getFormValueFromState(state)\n })\n\n repeaters.push(outputRepeaterItem)\n })\n\n return repeaters\n}\n\n/**\n * Returns the \"files\" section of the response body\n * @param item - the file upload item in the form\n * @returns the file upload data\n */\nfunction extractFileUploads(item: FileUploadFieldDetailitem) {\n const fileUploadState = item.field.getContextValueFromState(item.state) ?? []\n\n return fileUploadState.map((fileId) => {\n return {\n fileId,\n userDownloadLink: `${designerUrl}/file-download/${fileId}`\n }\n })\n}\n\nfunction isFileUploadFieldItem(\n item: DetailItemField\n): item is FileUploadFieldDetailitem {\n return item.field instanceof FileUploadField\n}\n\n/**\n * A detail item specifically for files\n */\ntype FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\n\ntype RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n"],"mappings":"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","ignoreList":[]}