@defra/forms-engine-plugin 4.23.0 → 5.0.0-alpha.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 (347) hide show
  1. package/.public/assets-manifest.json +3 -5
  2. package/.public/javascripts/im-core.min.js +2 -0
  3. package/.public/javascripts/im-core.min.js.map +1 -0
  4. package/.public/javascripts/shared.min.js +1 -1
  5. package/.public/javascripts/shared.min.js.map +1 -1
  6. package/.public/javascripts/vendor/@defra.min.js +1 -1
  7. package/.public/javascripts/vendor/@defra.min.js.map +1 -1
  8. package/.public/stylesheets/application.min.css +1 -1
  9. package/.public/stylesheets/application.min.css.map +1 -1
  10. package/.server/client/javascripts/geospatial-map.js +8 -6
  11. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  12. package/.server/client/javascripts/location-map.js +8 -1
  13. package/.server/client/javascripts/location-map.js.map +1 -1
  14. package/.server/client/javascripts/map.d.ts +6 -0
  15. package/.server/client/javascripts/map.js +10 -0
  16. package/.server/client/javascripts/map.js.map +1 -1
  17. package/.server/client/javascripts/sssi-dataset.d.ts +34 -0
  18. package/.server/client/javascripts/sssi-dataset.js +101 -0
  19. package/.server/client/javascripts/sssi-dataset.js.map +1 -0
  20. package/.server/client/stylesheets/shared.scss +0 -2
  21. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  22. package/.server/server/forms/simple-form.yaml +106 -3
  23. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +11 -11
  24. package/.server/server/plugins/engine/components/AutocompleteField.js +2 -2
  25. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  26. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +3 -2
  27. package/.server/server/plugins/engine/components/CheckboxesField.js +4 -9
  28. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  29. package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -7
  30. package/.server/server/plugins/engine/components/ComponentCollection.js +106 -51
  31. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  32. package/.server/server/plugins/engine/components/DatePartsField.d.ts +8 -6
  33. package/.server/server/plugins/engine/components/DatePartsField.js +27 -9
  34. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  35. package/.server/server/plugins/engine/components/DeclarationField.d.ts +13 -11
  36. package/.server/server/plugins/engine/components/DeclarationField.js +31 -9
  37. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  38. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +8 -5
  39. package/.server/server/plugins/engine/components/EastingNorthingField.js +42 -22
  40. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  41. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +11 -14
  42. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -2
  43. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  44. package/.server/server/plugins/engine/components/FileUploadField.d.ts +14 -12
  45. package/.server/server/plugins/engine/components/FileUploadField.js +22 -12
  46. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/FormComponent.d.ts +21 -12
  48. package/.server/server/plugins/engine/components/FormComponent.js +33 -14
  49. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  50. package/.server/server/plugins/engine/components/GeospatialField.d.ts +15 -12
  51. package/.server/server/plugins/engine/components/GeospatialField.js +21 -13
  52. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  53. package/.server/server/plugins/engine/components/LatLongField.d.ts +8 -5
  54. package/.server/server/plugins/engine/components/LatLongField.js +32 -20
  55. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  56. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +7 -6
  57. package/.server/server/plugins/engine/components/ListFormComponent.js +19 -7
  58. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  59. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +17 -16
  60. package/.server/server/plugins/engine/components/LocationFieldBase.js +2 -2
  61. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  62. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +8 -3
  63. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +14 -3
  64. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  65. package/.server/server/plugins/engine/components/Markdown.d.ts +8 -7
  66. package/.server/server/plugins/engine/components/Markdown.js +5 -2
  67. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  68. package/.server/server/plugins/engine/components/MonthYearField.d.ts +9 -7
  69. package/.server/server/plugins/engine/components/MonthYearField.js +26 -8
  70. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  71. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +10 -9
  72. package/.server/server/plugins/engine/components/MultilineTextField.js +2 -2
  73. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
  74. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  75. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +14 -6
  76. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  77. package/.server/server/plugins/engine/components/NumberField.d.ts +10 -9
  78. package/.server/server/plugins/engine/components/NumberField.js +2 -2
  79. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  80. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  81. package/.server/server/plugins/engine/components/OsGridRefField.js +14 -6
  82. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  83. package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -10
  84. package/.server/server/plugins/engine/components/PaymentField.js +21 -8
  85. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  86. package/.server/server/plugins/engine/components/SelectField.d.ts +11 -11
  87. package/.server/server/plugins/engine/components/SelectField.js +2 -2
  88. package/.server/server/plugins/engine/components/SelectField.js.map +1 -1
  89. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +4 -4
  90. package/.server/server/plugins/engine/components/SelectionControlField.js +2 -2
  91. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
  92. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +10 -9
  93. package/.server/server/plugins/engine/components/TelephoneNumberField.js +2 -2
  94. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
  95. package/.server/server/plugins/engine/components/UkAddressField.d.ts +12 -10
  96. package/.server/server/plugins/engine/components/UkAddressField.js +29 -17
  97. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  98. package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -0
  99. package/.server/server/plugins/engine/components/YesNoField.js +9 -0
  100. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  101. package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -2
  102. package/.server/server/plugins/engine/components/helpers/components.js +11 -8
  103. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  104. package/.server/server/plugins/engine/components/types.d.ts +8 -1
  105. package/.server/server/plugins/engine/components/types.js.map +1 -1
  106. package/.server/server/plugins/engine/configureEnginePlugin.js +8 -1
  107. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  108. package/.server/server/plugins/engine/form-context.d.ts +1 -0
  109. package/.server/server/plugins/engine/form-context.js +4 -2
  110. package/.server/server/plugins/engine/form-context.js.map +1 -1
  111. package/.server/server/plugins/engine/helpers.d.ts +1 -1
  112. package/.server/server/plugins/engine/helpers.js +8 -13
  113. package/.server/server/plugins/engine/helpers.js.map +1 -1
  114. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +39 -0
  115. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +50 -0
  116. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -0
  117. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +5 -0
  118. package/.server/server/plugins/engine/i18n/createFormTranslator.js +18 -0
  119. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -0
  120. package/.server/server/plugins/engine/i18n/createTranslator.d.ts +9 -0
  121. package/.server/server/plugins/engine/i18n/createTranslator.js +51 -0
  122. package/.server/server/plugins/engine/i18n/createTranslator.js.map +1 -0
  123. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +5 -0
  124. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +57 -0
  125. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -0
  126. package/.server/server/plugins/engine/i18n/index.d.ts +18 -0
  127. package/.server/server/plugins/engine/i18n/index.js +71 -0
  128. package/.server/server/plugins/engine/i18n/index.js.map +1 -0
  129. package/.server/server/plugins/engine/i18n/translations/cy.json +271 -0
  130. package/.server/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  131. package/.server/server/plugins/engine/i18n/types.d.ts +41 -0
  132. package/.server/server/plugins/engine/i18n/types.js +2 -0
  133. package/.server/server/plugins/engine/i18n/types.js.map +1 -0
  134. package/.server/server/plugins/engine/index.js +3 -2
  135. package/.server/server/plugins/engine/index.js.map +1 -1
  136. package/.server/server/plugins/engine/models/FormModel.d.ts +9 -1
  137. package/.server/server/plugins/engine/models/FormModel.js +44 -18
  138. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  139. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +5 -2
  140. package/.server/server/plugins/engine/models/SummaryViewModel.js +44 -18
  141. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  142. package/.server/server/plugins/engine/options.js +2 -1
  143. package/.server/server/plugins/engine/options.js.map +1 -1
  144. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +4 -0
  145. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  146. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  147. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  148. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +7 -6
  149. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
  150. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +2 -1
  151. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +6 -3
  152. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  153. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +3 -1
  154. package/.server/server/plugins/engine/pageControllers/PageController.js +11 -1
  155. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  156. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +4 -2
  157. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +52 -21
  158. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  159. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +3 -2
  160. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +63 -26
  161. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  162. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +3 -1
  163. package/.server/server/plugins/engine/pageControllers/StartPageController.js +2 -2
  164. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
  165. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +12 -2
  166. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
  167. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +4 -3
  168. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +44 -28
  169. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  170. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.d.ts +2 -0
  171. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js +24 -0
  172. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js.map +1 -0
  173. package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
  174. package/.server/server/plugins/engine/pageControllers/errors.js +3 -2
  175. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  176. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +3 -2
  177. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +4 -4
  178. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  179. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +7 -3
  180. package/.server/server/plugins/engine/pageControllers/validationOptions.js +34 -33
  181. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  182. package/.server/server/plugins/engine/plugin.js +2 -0
  183. package/.server/server/plugins/engine/plugin.js.map +1 -1
  184. package/.server/server/plugins/engine/routes/index.js +4 -1
  185. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  186. package/.server/server/plugins/engine/routes/questions.js +5 -2
  187. package/.server/server/plugins/engine/routes/questions.js.map +1 -1
  188. package/.server/server/plugins/engine/types/index.d.ts +1 -0
  189. package/.server/server/plugins/engine/types/index.js.map +1 -1
  190. package/.server/server/plugins/engine/types/schema.js +1 -0
  191. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  192. package/.server/server/plugins/engine/types.d.ts +12 -1
  193. package/.server/server/plugins/engine/types.js.map +1 -1
  194. package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
  195. package/.server/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  196. package/.server/server/plugins/engine/views/components/geospatialfield.html +4 -1
  197. package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  198. package/.server/server/plugins/engine/views/components/osgridreffield.html +1 -1
  199. package/.server/server/plugins/engine/views/components/paymentfield.html +8 -8
  200. package/.server/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  201. package/.server/server/plugins/engine/views/confirmation.html +4 -4
  202. package/.server/server/plugins/engine/views/exit.html +4 -4
  203. package/.server/server/plugins/engine/views/file-upload.html +3 -3
  204. package/.server/server/plugins/engine/views/index.html +3 -3
  205. package/.server/server/plugins/engine/views/item-delete.html +1 -1
  206. package/.server/server/plugins/engine/views/partials/form.html +3 -3
  207. package/.server/server/plugins/engine/views/partials/preview-banner.html +4 -4
  208. package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  209. package/.server/server/plugins/engine/views/repeat-list-summary.html +4 -4
  210. package/.server/server/plugins/engine/views/summary.html +14 -7
  211. package/.server/server/plugins/map/routes/index.js +1 -1
  212. package/.server/server/plugins/map/routes/index.js.map +1 -1
  213. package/.server/server/plugins/map/types.d.ts +1 -25
  214. package/.server/server/plugins/map/types.js +1 -16
  215. package/.server/server/plugins/map/types.js.map +1 -1
  216. package/.server/server/plugins/nunjucks/enviroment.test.js +10 -0
  217. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  218. package/.server/server/plugins/nunjucks/environment.d.ts +8 -0
  219. package/.server/server/plugins/nunjucks/environment.js +13 -0
  220. package/.server/server/plugins/nunjucks/environment.js.map +1 -1
  221. package/.server/server/plugins/nunjucks/filters/answer.js +9 -1
  222. package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
  223. package/.server/server/plugins/nunjucks/filters/answer.test.js +13 -2
  224. package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
  225. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  226. package/.server/server/plugins/postcode-lookup/models/index.d.ts +24 -19
  227. package/.server/server/plugins/postcode-lookup/models/index.js +83 -76
  228. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  229. package/.server/server/plugins/postcode-lookup/routes/index.js +7 -13
  230. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  231. package/.server/server/plugins/postcode-lookup/types.d.ts +1 -0
  232. package/.server/server/plugins/postcode-lookup/types.js +1 -0
  233. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  234. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  235. package/.server/server/types.d.ts +2 -1
  236. package/.server/server/types.js.map +1 -1
  237. package/.server/server/utils/utils.d.ts +5 -0
  238. package/.server/server/utils/utils.js +16 -0
  239. package/.server/server/utils/utils.js.map +1 -1
  240. package/.server/typings/hapi/index.d.js.map +1 -1
  241. package/package.json +5 -4
  242. package/src/client/javascripts/geospatial-map.js +10 -6
  243. package/src/client/javascripts/location-map.js +11 -0
  244. package/src/client/javascripts/map.js +10 -0
  245. package/src/client/javascripts/sssi-dataset.js +106 -0
  246. package/src/client/stylesheets/shared.scss +0 -2
  247. package/src/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  248. package/src/server/forms/simple-form.yaml +106 -3
  249. package/src/server/plugins/engine/components/AutocompleteField.ts +3 -6
  250. package/src/server/plugins/engine/components/CheckboxesField.ts +12 -11
  251. package/src/server/plugins/engine/components/ComponentCollection.ts +143 -61
  252. package/src/server/plugins/engine/components/DatePartsField.ts +33 -11
  253. package/src/server/plugins/engine/components/DeclarationField.ts +37 -14
  254. package/src/server/plugins/engine/components/EastingNorthingField.ts +83 -22
  255. package/src/server/plugins/engine/components/EmailAddressField.ts +4 -7
  256. package/src/server/plugins/engine/components/FileUploadField.ts +28 -22
  257. package/src/server/plugins/engine/components/FormComponent.ts +49 -12
  258. package/src/server/plugins/engine/components/GeospatialField.ts +38 -21
  259. package/src/server/plugins/engine/components/LatLongField.ts +52 -21
  260. package/src/server/plugins/engine/components/ListFormComponent.ts +26 -10
  261. package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -8
  262. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +24 -4
  263. package/src/server/plugins/engine/components/Markdown.ts +7 -3
  264. package/src/server/plugins/engine/components/MonthYearField.ts +32 -10
  265. package/src/server/plugins/engine/components/MultilineTextField.ts +5 -8
  266. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +25 -11
  267. package/src/server/plugins/engine/components/NumberField.ts +3 -4
  268. package/src/server/plugins/engine/components/OsGridRefField.ts +25 -9
  269. package/src/server/plugins/engine/components/PaymentField.ts +22 -12
  270. package/src/server/plugins/engine/components/SelectField.ts +3 -6
  271. package/src/server/plugins/engine/components/SelectionControlField.ts +7 -8
  272. package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -7
  273. package/src/server/plugins/engine/components/UkAddressField.ts +33 -18
  274. package/src/server/plugins/engine/components/YesNoField.ts +10 -0
  275. package/src/server/plugins/engine/components/helpers/components.ts +13 -6
  276. package/src/server/plugins/engine/components/types.ts +9 -0
  277. package/src/server/plugins/engine/configureEnginePlugin.ts +12 -1
  278. package/src/server/plugins/engine/form-context.ts +8 -2
  279. package/src/server/plugins/engine/helpers.ts +10 -18
  280. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +69 -0
  281. package/src/server/plugins/engine/i18n/createFormTranslator.ts +33 -0
  282. package/src/server/plugins/engine/i18n/createTranslator.ts +61 -0
  283. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +61 -0
  284. package/src/server/plugins/engine/i18n/index.ts +80 -0
  285. package/src/server/plugins/engine/i18n/translations/cy.json +271 -0
  286. package/src/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  287. package/src/server/plugins/engine/i18n/types.ts +62 -0
  288. package/src/server/plugins/engine/index.ts +4 -2
  289. package/src/server/plugins/engine/models/FormModel.ts +59 -23
  290. package/src/server/plugins/engine/models/SummaryViewModel.ts +68 -25
  291. package/src/server/plugins/engine/options.js +2 -1
  292. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +5 -0
  293. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -3
  294. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +9 -8
  295. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +7 -3
  296. package/src/server/plugins/engine/pageControllers/PageController.ts +12 -1
  297. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +53 -21
  298. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +66 -29
  299. package/src/server/plugins/engine/pageControllers/StartPageController.ts +7 -2
  300. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +10 -2
  301. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +48 -22
  302. package/src/server/plugins/engine/pageControllers/__stubs__/translator.ts +28 -0
  303. package/src/server/plugins/engine/pageControllers/errors.ts +4 -2
  304. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +11 -4
  305. package/src/server/plugins/engine/pageControllers/validationOptions.ts +43 -53
  306. package/src/server/plugins/engine/plugin.ts +2 -0
  307. package/src/server/plugins/engine/routes/index.ts +9 -1
  308. package/src/server/plugins/engine/routes/questions.ts +5 -1
  309. package/src/server/plugins/engine/types/index.ts +5 -0
  310. package/src/server/plugins/engine/types/schema.ts +1 -0
  311. package/src/server/plugins/engine/types.ts +10 -0
  312. package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
  313. package/src/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  314. package/src/server/plugins/engine/views/components/geospatialfield.html +4 -1
  315. package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  316. package/src/server/plugins/engine/views/components/osgridreffield.html +1 -1
  317. package/src/server/plugins/engine/views/components/paymentfield.html +8 -8
  318. package/src/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  319. package/src/server/plugins/engine/views/confirmation.html +4 -4
  320. package/src/server/plugins/engine/views/exit.html +4 -4
  321. package/src/server/plugins/engine/views/file-upload.html +3 -3
  322. package/src/server/plugins/engine/views/index.html +3 -3
  323. package/src/server/plugins/engine/views/item-delete.html +1 -1
  324. package/src/server/plugins/engine/views/partials/form.html +3 -3
  325. package/src/server/plugins/engine/views/partials/preview-banner.html +4 -4
  326. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  327. package/src/server/plugins/engine/views/repeat-list-summary.html +4 -4
  328. package/src/server/plugins/engine/views/summary.html +14 -7
  329. package/src/server/plugins/map/routes/index.js +1 -1
  330. package/src/server/plugins/map/types.js +1 -16
  331. package/src/server/plugins/nunjucks/environment.js +14 -0
  332. package/src/server/plugins/nunjucks/filters/answer.js +12 -1
  333. package/src/server/plugins/postcode-lookup/models/index.js +144 -87
  334. package/src/server/plugins/postcode-lookup/routes/index.js +13 -16
  335. package/src/server/plugins/postcode-lookup/types.js +1 -0
  336. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  337. package/src/server/types.ts +2 -0
  338. package/src/server/utils/utils.js +14 -0
  339. package/src/typings/hapi/index.d.ts +1 -0
  340. package/.public/javascripts/im-search-plugin.min.js +0 -2
  341. package/.public/javascripts/im-search-plugin.min.js.map +0 -1
  342. package/.public/javascripts/vendor/preact.min.js +0 -2
  343. package/.public/javascripts/vendor/preact.min.js.map +0 -1
  344. package/.server/server/plugins/engine/components/constants.d.ts +0 -1
  345. package/.server/server/plugins/engine/components/constants.js +0 -2
  346. package/.server/server/plugins/engine/components/constants.js.map +0 -1
  347. package/src/server/plugins/engine/components/constants.ts +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"FormModel.js","names":["ComponentType","ConditionsModel","ControllerPath","ControllerType","SchemaVersion","convertConditionWrapperFromV2","formDefinitionSchema","formDefinitionV2Schema","generateConditionAlias","hasComponents","hasComponentsEvenIfNoNext","hasRepeater","isConditionWrapperV2","yesNoListId","yesNoListName","add","format","Parser","joi","logger","hasListFormField","todayAsDateOnly","findPage","getError","getPage","setPageTitles","createPage","validationOptions","opts","defaultServices","FormAction","merge","FormModel","engine","schemaVersion","def","lists","sections","name","formId","values","basePath","ordnanceSurveyApiKey","conditions","pages","services","controllers","pageDefMap","listDefMap","listDefIdMap","componentDefMap","componentDefIdMap","pageMap","componentMap","constructor","options","schema","V1","warn","result","validate","abortEarly","error","structuredClone","value","push","id","title","type","items","text","moreThanOnePaymentQuestion","Error","Map","map","page","path","list","filter","flatMap","components","component","forEach","conditionDef","condition","makeCondition","pageDef","some","controller","Status","collection","makeFilteredSchema","relevantPages","object","required","concat","stateSchema","parser","operators","logical","Object","assign","functions","dateForComparison","timePeriod","timeUnit","displayName","expr","toConditionExpression","fn","evaluationState","ctx","toConditionContext","evaluate","context","conditionId","propertyName","V2","defineProperty","get","from","parse","toExpression","getList","nameOrId","find","getSection","section","getFormContext","request","state","errors","query","currentPath","startPath","getStartPath","isForceAccess","relevantState","payload","getFormDataFromState","paths","data","referenceNumber","getReferenceNumber","validateFormPayload","nextPage","initialiseContext","assignEvaluationState","assignRelevantState","pageStateIsInvalid","getNextPath","validateFormState","assignPaths","emptyState","freeze","getContextValueFromState","key","keys","listFields","fields","field","undefined","YesNoField","hasOptionalItems","item","length","fieldStateIsInvalid","validValues","fieldState","getFormValueFromState","isInvalid","isArray","Array","every","includes","href","getComponentById","componentId","getListById","listId","getConditionById","numOfPaymentFields","comp","PaymentField","action","getFormParams","Validate","startsWith","External","update","CheckboxesField","formState","getStateFromValidForm","previousPages","relevantPage","model","stripUnknown","errorsState","details","$$__referenceNumber"],"sources":["../../../../../src/server/plugins/engine/models/FormModel.ts"],"sourcesContent":["import {\n ComponentType,\n ConditionsModel,\n ControllerPath,\n ControllerType,\n SchemaVersion,\n convertConditionWrapperFromV2,\n formDefinitionSchema,\n formDefinitionV2Schema,\n generateConditionAlias,\n hasComponents,\n hasComponentsEvenIfNoNext,\n hasRepeater,\n isConditionWrapperV2,\n yesNoListId,\n yesNoListName,\n type ComponentDef,\n type ConditionWrapper,\n type ConditionWrapperV2,\n type ConditionsModelData,\n type DateUnits,\n type Engine,\n type FormDefinition,\n type List,\n type Page,\n type Section\n} from '@defra/forms-model'\nimport { add, format } from 'date-fns'\nimport { Parser, type Value } from 'expr-eval-fork'\nimport joi from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { type ListFormComponent } from '~/src/server/plugins/engine/components/ListFormComponent.js'\nimport {} from '~/src/server/plugins/engine/components/YesNoField.js'\nimport {\n hasListFormField,\n type Component\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { todayAsDateOnly } from '~/src/server/plugins/engine/date-helper.js'\nimport {\n findPage,\n getError,\n getPage,\n setPageTitles\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/pages.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 schemaVersion: SchemaVersion\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 formId: string\n values: FormDefinition\n basePath: string\n ordnanceSurveyApiKey?: 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\n listDefMap: Map<string, List>\n listDefIdMap: Map<string, List>\n\n componentDefMap: Map<string, ComponentDef>\n componentDefIdMap: Map<string, ComponentDef>\n\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n\n constructor(\n def: typeof this.def,\n options: {\n basePath: string\n ordnanceSurveyApiKey?: string\n formId?: string\n },\n services: Services = defaultServices,\n controllers?: Record<string, typeof PageController>\n ) {\n let schema = formDefinitionV2Schema\n\n if (!def.schema || def.schema === SchemaVersion.V1) {\n logger.warn(\n `[DEPRECATION NOTICE] Form \"${def.name}\" constructed with legacy V1 schema. See https://defra.github.io/forms-engine-plugin/schemas/form-definition-schema.html.`\n )\n schema = formDefinitionSchema\n }\n\n const result = schema.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 id: def.schema === SchemaVersion.V1 ? yesNoListName : yesNoListId,\n name: '__yesNo',\n title: 'Yes/No',\n type: 'boolean',\n items: [\n {\n id: '02900d42-83d1-4c72-a719-c4e8228952fa',\n text: 'Yes',\n value: true\n },\n {\n id: 'f39000eb-c51b-4019-8f82-bbda0423f04d',\n text: 'No',\n value: false\n }\n ]\n })\n\n // Fix up page titles\n setPageTitles(def)\n\n this.engine = def.engine\n this.schemaVersion = def.schema ?? SchemaVersion.V1\n this.def = def\n this.lists = def.lists\n this.sections = def.sections\n this.name = def.name ?? ''\n this.formId = options.formId ?? ''\n this.values = result.value\n this.basePath = options.basePath\n this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey\n this.conditions = {}\n this.services = services\n this.controllers = controllers\n\n // Assert that there is only one payment question (if any)\n if (this.moreThanOnePaymentQuestion()) {\n throw new Error(\n 'Invalid form definition: Only one payment question is allowed per form'\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.listDefIdMap = new Map(\n def.lists\n .filter((list) => list.id) // Skip lists without an ID\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n .map((list) => [list.id as string, list])\n )\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 this.componentDefIdMap = new Map(\n def.pages.filter(hasComponents).flatMap((page) =>\n page.components\n .filter((component) => component.id) // Skip components without an ID\n .map((component) => {\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return [component.id as string, component]\n })\n )\n )\n\n def.conditions.forEach((conditionDef) => {\n const condition = this.makeCondition(\n isConditionWrapperV2(conditionDef)\n ? convertConditionWrapperFromV2(conditionDef, this)\n : conditionDef\n )\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.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 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 // The time element must be stripped (hence using startOfDay() which has no time element),\n // then formatted as YYYY-MM-DD otherwise we can hit time element and BST issues giving the\n // wrong date to compare against.\n // Do not use .toISOString() to format the date as that introduces BST errors.\n return format(\n add(todayAsDateOnly(), { [timeUnit]: timePeriod }),\n 'yyyy-MM-dd'\n )\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 conditionId in conditions) {\n const propertyName =\n this.schemaVersion === SchemaVersion.V2\n ? generateConditionAlias(conditionId)\n : conditionId\n\n Object.defineProperty(context, propertyName, {\n get() {\n return conditions[conditionId]?.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(nameOrId: string): List | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.lists.find((list) => list.name === nameOrId)\n : this.lists.find((list) => list.id === nameOrId)\n }\n\n getSection(nameOrId: string): Section | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.sections.find((section) => section.name === nameOrId)\n : this.sections.find((section) => section.id === nameOrId)\n }\n\n /**\n * Form context for the current page\n */\n getFormContext(\n request: FormContextRequest,\n state: FormSubmissionState,\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 referenceNumber: getReferenceNumber(state)\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 (\n this.pageStateIsInvalid(context, nextPage) ||\n nextPage.path === currentPath\n ) {\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 // Initialise `evaluationState` for all keys using empty state.\n // This is because the current condition evaluation library (eval-expr)\n // will throw if an expression uses a key that is undefined.\n const emptyState = Object.freeze({})\n\n for (const page of this.pages) {\n const { collection, pageDef } = page\n\n if (!hasRepeater(pageDef)) {\n Object.assign(\n context.evaluationState,\n collection.getContextValueFromState(emptyState)\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 pageStateIsInvalid(context: FormContext, page: PageControllerClass) {\n // Get any list-bound fields on the page\n const listFields = page.collection.fields.filter(hasListFormField)\n\n // For each list field that is bound to a list that contains any conditional items,\n // we need to check any answers are still valid. Do this by evaluating the conditions\n // and ensuring any current answers are all included in the set of valid answers\n for (const field of listFields) {\n const list = field.list\n\n // Filter out YesNo as they can't be conditional\n if (list !== undefined && field.type !== ComponentType.YesNoField) {\n const hasOptionalItems =\n list.items.filter((item) => item.condition).length > 0\n\n if (hasOptionalItems) {\n return this.fieldStateIsInvalid(context, field, list)\n }\n }\n }\n }\n\n private fieldStateIsInvalid(\n context: FormContext,\n field: ListFormComponent,\n list: List\n ) {\n const { evaluationState, state } = context\n\n const validValues = list.items\n .filter((item) =>\n item.condition\n ? this.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n .map((item) => item.value)\n\n // Get the field state\n const fieldState = field.getFormValueFromState(state)\n\n if (fieldState !== undefined) {\n let isInvalid = false\n const isArray = Array.isArray(fieldState)\n\n // Check if any saved state value(s) are still valid\n // and return true if any are invalid\n if (isArray) {\n isInvalid = !fieldState.every((item) => validValues.includes(item))\n } else {\n isInvalid = !validValues.includes(fieldState)\n }\n\n if (isInvalid) {\n context.errors ??= []\n\n const text =\n 'Options are different because you changed a previous answer'\n\n context.errors.push({\n text,\n name: field.name,\n href: `#${field.name}`,\n path: [`#${field.name}`]\n })\n }\n\n return isInvalid\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 getComponentById(componentId: string): ComponentDef | undefined {\n return this.componentDefIdMap.get(componentId)\n }\n\n getListById(listId: string): List | undefined {\n return this.listDefIdMap.get(listId)\n }\n\n /**\n * Returns a condition by its ID. O(n) lookup time.\n * @param conditionId\n * @returns\n */\n getConditionById(conditionId: string): ConditionWrapperV2 | undefined {\n return this.def.conditions\n .filter(isConditionWrapperV2)\n .find((condition) => condition.id === conditionId)\n }\n\n /**\n * Checks that only one payment field exists (if any payments fields exist)\n */\n moreThanOnePaymentQuestion() {\n const numOfPaymentFields = this.def.pages\n .flatMap((page) =>\n hasComponentsEvenIfNoNext(page) ? page.components : []\n )\n .filter((comp) => comp.type === ComponentType.PaymentField).length\n return numOfPaymentFields > 1\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 (\n !request.payload ||\n (action &&\n action !== FormAction.Validate &&\n !action.startsWith(FormAction.External))\n ) {\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\nfunction getReferenceNumber(state: FormSubmissionState): string {\n if (\n !state.$$__referenceNumber ||\n typeof state.$$__referenceNumber !== 'string'\n ) {\n throw Error('Reference number not found in form state')\n }\n\n return state.$$__referenceNumber\n}\n"],"mappings":"AAAA,SACEA,aAAa,EACbC,eAAe,EACfC,cAAc,EACdC,cAAc,EACdC,aAAa,EACbC,6BAA6B,EAC7BC,oBAAoB,EACpBC,sBAAsB,EACtBC,sBAAsB,EACtBC,aAAa,EACbC,yBAAyB,EACzBC,WAAW,EACXC,oBAAoB,EACpBC,WAAW,EACXC,aAAa,QAWR,oBAAoB;AAC3B,SAASC,GAAG,EAAEC,MAAM,QAAQ,UAAU;AACtC,SAASC,MAAM,QAAoB,gBAAgB;AACnD,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,MAAM;AAEf;AACA,SACEC,gBAAgB;AAGlB,SAASC,eAAe;AACxB,SACEC,QAAQ,EACRC,QAAQ,EACRC,OAAO,EACPC,aAAa;AAIf,SACEC,UAAU;AAGZ,SAASC,iBAAiB,IAAIC,IAAI;AAClC,OAAO,KAAKC,eAAe;AAQ3B,SAASC,UAAU;AACnB,SAASC,KAAK;AAGd,OAAO,MAAMC,SAAS,CAAC;EACrB;EACAC,MAAM;EAENC,aAAa;;EAEb;EACAC,GAAG;EAEHC,KAAK;EACLC,QAAQ,GAA+B,EAAE;EACzCC,IAAI;EACJC,MAAM;EACNC,MAAM;EACNC,QAAQ;EACRC,oBAAoB;EACpBC,UAAU;EACVC,KAAK;EACLC,QAAQ;EAERC,WAAW;EACXC,UAAU;EAEVC,UAAU;EACVC,YAAY;EAEZC,eAAe;EACfC,iBAAiB;EAEjBC,OAAO;EACPC,YAAY;EAEZC,WAAWA,CACTnB,GAAoB,EACpBoB,OAIC,EACDV,QAAkB,GAAGhB,eAAe,EACpCiB,WAAmD,EACnD;IACA,IAAIU,MAAM,GAAGjD,sBAAsB;IAEnC,IAAI,CAAC4B,GAAG,CAACqB,MAAM,IAAIrB,GAAG,CAACqB,MAAM,KAAKpD,aAAa,CAACqD,EAAE,EAAE;MAClDtC,MAAM,CAACuC,IAAI,CACT,8BAA8BvB,GAAG,CAACG,IAAI,2HACxC,CAAC;MACDkB,MAAM,GAAGlD,oBAAoB;IAC/B;IAEA,MAAMqD,MAAM,GAAGH,MAAM,CAACI,QAAQ,CAACzB,GAAG,EAAE;MAAE0B,UAAU,EAAE;IAAM,CAAC,CAAC;IAE1D,IAAIF,MAAM,CAACG,KAAK,EAAE;MAChB,MAAMH,MAAM,CAACG,KAAK;IACpB;;IAEA;IACA;IACA3B,GAAG,GAAG4B,eAAe,CAACJ,MAAM,CAACK,KAAK,CAAC;;IAEnC;IACA7B,GAAG,CAACC,KAAK,CAAC6B,IAAI,CAAC;MACbC,EAAE,EAAE/B,GAAG,CAACqB,MAAM,KAAKpD,aAAa,CAACqD,EAAE,GAAG3C,aAAa,GAAGD,WAAW;MACjEyB,IAAI,EAAE,SAAS;MACf6B,KAAK,EAAE,QAAQ;MACfC,IAAI,EAAE,SAAS;MACfC,KAAK,EAAE,CACL;QACEH,EAAE,EAAE,sCAAsC;QAC1CI,IAAI,EAAE,KAAK;QACXN,KAAK,EAAE;MACT,CAAC,EACD;QACEE,EAAE,EAAE,sCAAsC;QAC1CI,IAAI,EAAE,IAAI;QACVN,KAAK,EAAE;MACT,CAAC;IAEL,CAAC,CAAC;;IAEF;IACAvC,aAAa,CAACU,GAAG,CAAC;IAElB,IAAI,CAACF,MAAM,GAAGE,GAAG,CAACF,MAAM;IACxB,IAAI,CAACC,aAAa,GAAGC,GAAG,CAACqB,MAAM,IAAIpD,aAAa,CAACqD,EAAE;IACnD,IAAI,CAACtB,GAAG,GAAGA,GAAG;IACd,IAAI,CAACC,KAAK,GAAGD,GAAG,CAACC,KAAK;IACtB,IAAI,CAACC,QAAQ,GAAGF,GAAG,CAACE,QAAQ;IAC5B,IAAI,CAACC,IAAI,GAAGH,GAAG,CAACG,IAAI,IAAI,EAAE;IAC1B,IAAI,CAACC,MAAM,GAAGgB,OAAO,CAAChB,MAAM,IAAI,EAAE;IAClC,IAAI,CAACC,MAAM,GAAGmB,MAAM,CAACK,KAAK;IAC1B,IAAI,CAACvB,QAAQ,GAAGc,OAAO,CAACd,QAAQ;IAChC,IAAI,CAACC,oBAAoB,GAAGa,OAAO,CAACb,oBAAoB;IACxD,IAAI,CAACC,UAAU,GAAG,CAAC,CAAC;IACpB,IAAI,CAACE,QAAQ,GAAGA,QAAQ;IACxB,IAAI,CAACC,WAAW,GAAGA,WAAW;;IAE9B;IACA,IAAI,IAAI,CAACyB,0BAA0B,CAAC,CAAC,EAAE;MACrC,MAAM,IAAIC,KAAK,CACb,wEACF,CAAC;IACH;IAEA,IAAI,CAACzB,UAAU,GAAG,IAAI0B,GAAG,CAACtC,GAAG,CAACS,KAAK,CAAC8B,GAAG,CAAEC,IAAI,IAAK,CAACA,IAAI,CAACC,IAAI,EAAED,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC3B,UAAU,GAAG,IAAIyB,GAAG,CAACtC,GAAG,CAACC,KAAK,CAACsC,GAAG,CAAEG,IAAI,IAAK,CAACA,IAAI,CAACvC,IAAI,EAAEuC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC5B,YAAY,GAAG,IAAIwB,GAAG,CACzBtC,GAAG,CAACC,KAAK,CACN0C,MAAM,CAAED,IAAI,IAAKA,IAAI,CAACX,EAAE,CAAC,CAAC;IAC3B;IAAA,CACCQ,GAAG,CAAEG,IAAI,IAAK,CAACA,IAAI,CAACX,EAAE,EAAYW,IAAI,CAAC,CAC5C,CAAC;IACD,IAAI,CAAC3B,eAAe,GAAG,IAAIuB,GAAG,CAC5BtC,GAAG,CAACS,KAAK,CACNkC,MAAM,CAACrE,aAAa,CAAC,CACrBsE,OAAO,CAAEJ,IAAI,IACZA,IAAI,CAACK,UAAU,CAACN,GAAG,CAAEO,SAAS,IAAK,CAACA,SAAS,CAAC3C,IAAI,EAAE2C,SAAS,CAAC,CAChE,CACJ,CAAC;IACD,IAAI,CAAC9B,iBAAiB,GAAG,IAAIsB,GAAG,CAC9BtC,GAAG,CAACS,KAAK,CAACkC,MAAM,CAACrE,aAAa,CAAC,CAACsE,OAAO,CAAEJ,IAAI,IAC3CA,IAAI,CAACK,UAAU,CACZF,MAAM,CAAEG,SAAS,IAAKA,SAAS,CAACf,EAAE,CAAC,CAAC;IAAA,CACpCQ,GAAG,CAAEO,SAAS,IAAK;MAClB;MACA,OAAO,CAACA,SAAS,CAACf,EAAE,EAAYe,SAAS,CAAC;IAC5C,CAAC,CACL,CACF,CAAC;IAED9C,GAAG,CAACQ,UAAU,CAACuC,OAAO,CAAEC,YAAY,IAAK;MACvC,MAAMC,SAAS,GAAG,IAAI,CAACC,aAAa,CAClCzE,oBAAoB,CAACuE,YAAY,CAAC,GAC9B9E,6BAA6B,CAAC8E,YAAY,EAAE,IAAI,CAAC,GACjDA,YACN,CAAC;MACD,IAAI,CAACxC,UAAU,CAACyC,SAAS,CAAC9C,IAAI,CAAC,GAAG8C,SAAS;IAC7C,CAAC,CAAC;IAEF,IAAI,CAACxC,KAAK,GAAGT,GAAG,CAACS,KAAK,CAAC8B,GAAG,CAAEY,OAAO,IAAK5D,UAAU,CAAC,IAAI,EAAE4D,OAAO,CAAC,CAAC;IAElE,IACE,CAACnD,GAAG,CAACS,KAAK,CAAC2C,IAAI,CACb,CAAC;MAAEC;IAAW,CAAC;IACb;IACAA,UAAU,KAAKrF,cAAc,CAACsF,MAClC,CAAC,EACD;MACA,IAAI,CAAC7C,KAAK,CAACqB,IAAI,CACbvC,UAAU,CAAC,IAAI,EAAE;QACfyC,KAAK,EAAE,gBAAgB;QACvBS,IAAI,EAAE1E,cAAc,CAACuF,MAAM;QAC3BD,UAAU,EAAErF,cAAc,CAACsF;MAC7B,CAAC,CACH,CAAC;IACH;IAEA,IAAI,CAACrC,OAAO,GAAG,IAAIqB,GAAG,CAAC,IAAI,CAAC7B,KAAK,CAAC8B,GAAG,CAAEC,IAAI,IAAK,CAACA,IAAI,CAACC,IAAI,EAAED,IAAI,CAAC,CAAC,CAAC;IACnE,IAAI,CAACtB,YAAY,GAAG,IAAIoB,GAAG,CACzB,IAAI,CAAC7B,KAAK,CAACmC,OAAO,CAAEJ,IAAI,IACtBA,IAAI,CAACe,UAAU,CAACV,UAAU,CAACN,GAAG,CAAEO,SAAS,IAAK,CAC5CA,SAAS,CAAC3C,IAAI,EACd2C,SAAS,CACV,CACH,CACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEU,kBAAkBA,CAACC,aAAoC,EAAE;IACvD;IACA;IACA,IAAIpC,MAAM,GAAGtC,GAAG,CAAC2E,MAAM,CAAsB,CAAC,CAACC,QAAQ,CAAC,CAAC;IAEzDF,aAAa,CAACV,OAAO,CAAEP,IAAI,IAAK;MAC9BnB,MAAM,GAAGA,MAAM,CAACuC,MAAM,CAACpB,IAAI,CAACe,UAAU,CAACM,WAAW,CAAC;IACrD,CAAC,CAAC;IAEF,OAAOxC,MAAM;EACf;;EAEA;AACF;AACA;AACA;EACE6B,aAAaA,CAACD,SAA2B,EAAuB;IAC9D,MAAMa,MAAM,GAAG,IAAIhF,MAAM,CAAC;MACxBiF,SAAS,EAAE;QACTC,OAAO,EAAE;MACX;IACF,CAAC,CAAC;IAEFC,MAAM,CAACC,MAAM,CAACJ,MAAM,CAACK,SAAS,EAAE;MAC9BC,iBAAiBA,CAACC,UAAkB,EAAEC,QAAmB,EAAE;QACzD;QACA;QACA;QACA;QACA,OAAOzF,MAAM,CACXD,GAAG,CAACM,eAAe,CAAC,CAAC,EAAE;UAAE,CAACoF,QAAQ,GAAGD;QAAW,CAAC,CAAC,EAClD,YACF,CAAC;MACH;IACF,CAAC,CAAC;IAEF,MAAM;MAAElE,IAAI;MAAEoE,WAAW;MAAE1C;IAAM,CAAC,GAAGoB,SAAS;IAC9C,MAAMuB,IAAI,GAAG,IAAI,CAACC,qBAAqB,CAAC5C,KAAK,EAAEiC,MAAM,CAAC;IAEtD,MAAMY,EAAE,GAAIC,eAA0B,IAAK;MACzC,MAAMC,GAAG,GAAG,IAAI,CAACC,kBAAkB,CAACF,eAAe,EAAE,IAAI,CAACnE,UAAU,CAAC;MACrE,IAAI;QACF,OAAOgE,IAAI,CAACM,QAAQ,CAACF,GAAG,CAAC;MAC3B,CAAC,CAAC,MAAM;QACN,OAAO,KAAK;MACd;IACF,CAAC;IAED,OAAO;MACLzE,IAAI;MACJoE,WAAW;MACX1C,KAAK;MACL2C,IAAI;MACJE;IACF,CAAC;EACH;EAEAG,kBAAkBA,CAChBF,eAA0B,EAC1BnE,UAAwD,EACxD;IACA,MAAMuE,OAAO,GAAG;MAAE,GAAGJ;IAAgB,CAAC;IAEtC,KAAK,MAAMK,WAAW,IAAIxE,UAAU,EAAE;MACpC,MAAMyE,YAAY,GAChB,IAAI,CAAClF,aAAa,KAAK9B,aAAa,CAACiH,EAAE,GACnC7G,sBAAsB,CAAC2G,WAAW,CAAC,GACnCA,WAAW;MAEjBf,MAAM,CAACkB,cAAc,CAACJ,OAAO,EAAEE,YAAY,EAAE;QAC3CG,GAAGA,CAAA,EAAG;UACJ,OAAO5E,UAAU,CAACwE,WAAW,CAAC,EAAEN,EAAE,CAACC,eAAe,CAAC;QACrD;MACF,CAAC,CAAC;IACJ;IAEA,OAAOI,OAAO;EAChB;EAEAN,qBAAqBA,CAAC5C,KAA0B,EAAEiC,MAAc,EAAE;IAChE,MAAMtD,UAAU,GAAG1C,eAAe,CAACuH,IAAI,CAACxD,KAAK,CAAC;IAC9C,OAAOiC,MAAM,CAACwB,KAAK,CAAC9E,UAAU,CAAC+E,YAAY,CAAC,CAAC,CAAC;EAChD;EAEAC,OAAOA,CAACC,QAAgB,EAAoB;IAC1C,OAAO,IAAI,CAAC1F,aAAa,KAAK9B,aAAa,CAACqD,EAAE,GAC1C,IAAI,CAACrB,KAAK,CAACyF,IAAI,CAAEhD,IAAI,IAAKA,IAAI,CAACvC,IAAI,KAAKsF,QAAQ,CAAC,GACjD,IAAI,CAACxF,KAAK,CAACyF,IAAI,CAAEhD,IAAI,IAAKA,IAAI,CAACX,EAAE,KAAK0D,QAAQ,CAAC;EACrD;EAEAE,UAAUA,CAACF,QAAgB,EAAuB;IAChD,OAAO,IAAI,CAAC1F,aAAa,KAAK9B,aAAa,CAACqD,EAAE,GAC1C,IAAI,CAACpB,QAAQ,CAACwF,IAAI,CAAEE,OAAO,IAAKA,OAAO,CAACzF,IAAI,KAAKsF,QAAQ,CAAC,GAC1D,IAAI,CAACvF,QAAQ,CAACwF,IAAI,CAAEE,OAAO,IAAKA,OAAO,CAAC7D,EAAE,KAAK0D,QAAQ,CAAC;EAC9D;;EAEA;AACF;AACA;EACEI,cAAcA,CACZC,OAA2B,EAC3BC,KAA0B,EAC1BC,MAA8B,EACjB;IACb,MAAM;MAAEC;IAAM,CAAC,GAAGH,OAAO;IAEzB,MAAMtD,IAAI,GAAGnD,OAAO,CAAC,IAAI,EAAEyG,OAAO,CAAC;;IAEnC;IACA,MAAMI,WAAW,GAAG1D,IAAI,CAACC,IAAI;IAC7B,MAAM0D,SAAS,GAAG3D,IAAI,CAAC4D,YAAY,CAAC,CAAC;;IAErC;IACA,MAAMC,aAAa,GAAG,OAAO,IAAIJ,KAAK;IAEtC,IAAIlB,OAAoB,GAAG;MACzBJ,eAAe,EAAE,CAAC,CAAC;MACnB2B,aAAa,EAAE,CAAC,CAAC;MACjB7C,aAAa,EAAE,EAAE;MACjB8C,OAAO,EAAE/D,IAAI,CAACgE,oBAAoB,CAACV,OAAO,EAAEC,KAAK,CAAC;MAClDA,KAAK;MACLU,KAAK,EAAE,EAAE;MACTT,MAAM;MACNK,aAAa;MACbK,IAAI,EAAE,CAAC,CAAC;MACR9F,UAAU,EAAE,IAAI,CAACA,UAAU;MAC3BC,UAAU,EAAE,IAAI,CAACA,UAAU;MAC3BE,eAAe,EAAE,IAAI,CAACA,eAAe;MACrCE,OAAO,EAAE,IAAI,CAACA,OAAO;MACrBC,YAAY,EAAE,IAAI,CAACA,YAAY;MAC/ByF,eAAe,EAAEC,kBAAkB,CAACb,KAAK;IAC3C,CAAC;;IAED;IACAhB,OAAO,GAAG8B,mBAAmB,CAACf,OAAO,EAAEtD,IAAI,EAAEuC,OAAO,CAAC;;IAErD;IACA,IAAI+B,QAAQ,GAAG3H,QAAQ,CAAC,IAAI,EAAEgH,SAAS,CAAC;IAExC,IAAI,CAACY,iBAAiB,CAAChC,OAAO,CAAC;;IAE/B;IACA,OAAO+B,QAAQ,EAAE;MACf;MACA/B,OAAO,CAACtB,aAAa,CAAC3B,IAAI,CAACgF,QAAQ,CAAC;MAEpC,IAAI,CAACE,qBAAqB,CAACjC,OAAO,EAAE+B,QAAQ,CAAC;MAE7C,IAAI,CAACG,mBAAmB,CAAClC,OAAO,EAAE+B,QAAQ,CAAC;;MAE3C;MACA,IACE,IAAI,CAACI,kBAAkB,CAACnC,OAAO,EAAE+B,QAAQ,CAAC,IAC1CA,QAAQ,CAACrE,IAAI,KAAKyD,WAAW,EAC7B;QACA;MACF;;MAEA;MACAY,QAAQ,GAAG3H,QAAQ,CAAC,IAAI,EAAE2H,QAAQ,CAACK,WAAW,CAACpC,OAAO,CAAC,CAAC;IAC1D;;IAEA;IACAA,OAAO,GAAGqC,iBAAiB,CAACtB,OAAO,EAAEtD,IAAI,EAAEuC,OAAO,CAAC;;IAEnD;IACA,IAAI,CAACsC,WAAW,CAACtC,OAAO,CAAC;IAEzB,OAAOA,OAAO;EAChB;EAEQgC,iBAAiBA,CAAChC,OAAoB,EAAE;IAC9C;IACA;IACA;IACA,MAAMuC,UAAU,GAAGrD,MAAM,CAACsD,MAAM,CAAC,CAAC,CAAC,CAAC;IAEpC,KAAK,MAAM/E,IAAI,IAAI,IAAI,CAAC/B,KAAK,EAAE;MAC7B,MAAM;QAAE8C,UAAU;QAAEJ;MAAQ,CAAC,GAAGX,IAAI;MAEpC,IAAI,CAAChE,WAAW,CAAC2E,OAAO,CAAC,EAAE;QACzBc,MAAM,CAACC,MAAM,CACXa,OAAO,CAACJ,eAAe,EACvBpB,UAAU,CAACiE,wBAAwB,CAACF,UAAU,CAChD,CAAC;MACH;IACF;EACF;EAEQN,qBAAqBA,CAC3BjC,OAAoB,EACpBvC,IAAyB,EACzB;IACA,MAAM;MAAEe,UAAU;MAAEJ;IAAQ,CAAC,GAAGX,IAAI;IACpC;;IAEA,IAAI,CAAChE,WAAW,CAAC2E,OAAO,CAAC,EAAE;MACzBc,MAAM,CAACC,MAAM,CACXa,OAAO,CAACJ,eAAe,EACvBpB,UAAU,CAACiE,wBAAwB,CAACzC,OAAO,CAACgB,KAAK,CACnD,CAAC;IACH;EACF;EAEQkB,mBAAmBA,CAAClC,OAAoB,EAAEvC,IAAyB,EAAE;IAC3E;IACA,KAAK,MAAMiF,GAAG,IAAIjF,IAAI,CAACkF,IAAI,EAAE;MAC3B,IAAI,OAAO3C,OAAO,CAACgB,KAAK,CAAC0B,GAAG,CAAC,KAAK,WAAW,EAAE;QAC7C1C,OAAO,CAACuB,aAAa,CAACmB,GAAG,CAAC,GAAG1C,OAAO,CAACgB,KAAK,CAAC0B,GAAG,CAAC;MACjD;IACF;EACF;EAEQP,kBAAkBA,CAACnC,OAAoB,EAAEvC,IAAyB,EAAE;IAC1E;IACA,MAAMmF,UAAU,GAAGnF,IAAI,CAACe,UAAU,CAACqE,MAAM,CAACjF,MAAM,CAAC1D,gBAAgB,CAAC;;IAElE;IACA;IACA;IACA,KAAK,MAAM4I,KAAK,IAAIF,UAAU,EAAE;MAC9B,MAAMjF,IAAI,GAAGmF,KAAK,CAACnF,IAAI;;MAEvB;MACA,IAAIA,IAAI,KAAKoF,SAAS,IAAID,KAAK,CAAC5F,IAAI,KAAKpE,aAAa,CAACkK,UAAU,EAAE;QACjE,MAAMC,gBAAgB,GACpBtF,IAAI,CAACR,KAAK,CAACS,MAAM,CAAEsF,IAAI,IAAKA,IAAI,CAAChF,SAAS,CAAC,CAACiF,MAAM,GAAG,CAAC;QAExD,IAAIF,gBAAgB,EAAE;UACpB,OAAO,IAAI,CAACG,mBAAmB,CAACpD,OAAO,EAAE8C,KAAK,EAAEnF,IAAI,CAAC;QACvD;MACF;IACF;EACF;EAEQyF,mBAAmBA,CACzBpD,OAAoB,EACpB8C,KAAwB,EACxBnF,IAAU,EACV;IACA,MAAM;MAAEiC,eAAe;MAAEoB;IAAM,CAAC,GAAGhB,OAAO;IAE1C,MAAMqD,WAAW,GAAG1F,IAAI,CAACR,KAAK,CAC3BS,MAAM,CAAEsF,IAAI,IACXA,IAAI,CAAChF,SAAS,GACV,IAAI,CAACzC,UAAU,CAACyH,IAAI,CAAChF,SAAS,CAAC,EAAEyB,EAAE,CAACC,eAAe,CAAC,GACpD,IACN,CAAC,CACApC,GAAG,CAAE0F,IAAI,IAAKA,IAAI,CAACpG,KAAK,CAAC;;IAE5B;IACA,MAAMwG,UAAU,GAAGR,KAAK,CAACS,qBAAqB,CAACvC,KAAK,CAAC;IAErD,IAAIsC,UAAU,KAAKP,SAAS,EAAE;MAC5B,IAAIS,SAAS,GAAG,KAAK;MACrB,MAAMC,OAAO,GAAGC,KAAK,CAACD,OAAO,CAACH,UAAU,CAAC;;MAEzC;MACA;MACA,IAAIG,OAAO,EAAE;QACXD,SAAS,GAAG,CAACF,UAAU,CAACK,KAAK,CAAET,IAAI,IAAKG,WAAW,CAACO,QAAQ,CAACV,IAAI,CAAC,CAAC;MACrE,CAAC,MAAM;QACLM,SAAS,GAAG,CAACH,WAAW,CAACO,QAAQ,CAACN,UAAU,CAAC;MAC/C;MAEA,IAAIE,SAAS,EAAE;QACbxD,OAAO,CAACiB,MAAM,KAAK,EAAE;QAErB,MAAM7D,IAAI,GACR,6DAA6D;QAE/D4C,OAAO,CAACiB,MAAM,CAAClE,IAAI,CAAC;UAClBK,IAAI;UACJhC,IAAI,EAAE0H,KAAK,CAAC1H,IAAI;UAChByI,IAAI,EAAE,IAAIf,KAAK,CAAC1H,IAAI,EAAE;UACtBsC,IAAI,EAAE,CAAC,IAAIoF,KAAK,CAAC1H,IAAI,EAAE;QACzB,CAAC,CAAC;MACJ;MAEA,OAAOoI,SAAS;IAClB;EACF;EAEQlB,WAAWA,CAACtC,OAAoB,EAAE;IACxC,KAAK,MAAM;MAAE2C,IAAI;MAAEjF;IAAK,CAAC,IAAIsC,OAAO,CAACtB,aAAa,EAAE;MAClDsB,OAAO,CAAC0B,KAAK,CAAC3E,IAAI,CAACW,IAAI,CAAC;;MAExB;MACA,IACEsC,OAAO,CAACiB,MAAM,EAAE5C,IAAI,CAAC,CAAC;QAAEjD,IAAI;QAAEsC;MAAK,CAAC,KAAK;QACvC,OAAOiF,IAAI,CAACiB,QAAQ,CAACxI,IAAI,CAAC,IAAIuH,IAAI,CAACtE,IAAI,CAAEqE,GAAG,IAAKhF,IAAI,CAACkG,QAAQ,CAAClB,GAAG,CAAC,CAAC;MACtE,CAAC,CAAC,EACF;QACA;MACF;IACF;EACF;EAEAoB,gBAAgBA,CAACC,WAAmB,EAA4B;IAC9D,OAAO,IAAI,CAAC9H,iBAAiB,CAACoE,GAAG,CAAC0D,WAAW,CAAC;EAChD;EAEAC,WAAWA,CAACC,MAAc,EAAoB;IAC5C,OAAO,IAAI,CAAClI,YAAY,CAACsE,GAAG,CAAC4D,MAAM,CAAC;EACtC;;EAEA;AACF;AACA;AACA;AACA;EACEC,gBAAgBA,CAACjE,WAAmB,EAAkC;IACpE,OAAO,IAAI,CAAChF,GAAG,CAACQ,UAAU,CACvBmC,MAAM,CAAClE,oBAAoB,CAAC,CAC5BiH,IAAI,CAAEzC,SAAS,IAAKA,SAAS,CAAClB,EAAE,KAAKiD,WAAW,CAAC;EACtD;;EAEA;AACF;AACA;EACE5C,0BAA0BA,CAAA,EAAG;IAC3B,MAAM8G,kBAAkB,GAAG,IAAI,CAAClJ,GAAG,CAACS,KAAK,CACtCmC,OAAO,CAAEJ,IAAI,IACZjE,yBAAyB,CAACiE,IAAI,CAAC,GAAGA,IAAI,CAACK,UAAU,GAAG,EACtD,CAAC,CACAF,MAAM,CAAEwG,IAAI,IAAKA,IAAI,CAAClH,IAAI,KAAKpE,aAAa,CAACuL,YAAY,CAAC,CAAClB,MAAM;IACpE,OAAOgB,kBAAkB,GAAG,CAAC;EAC/B;AACF;;AAEA;AACA;AACA;AACA,SAASrC,mBAAmBA,CAC1Bf,OAA2B,EAC3BtD,IAAyB,EACzBuC,OAAoB,EACP;EACb,MAAM;IAAExB;EAAW,CAAC,GAAGf,IAAI;EAC3B,MAAM;IAAE+D,OAAO;IAAER;EAAM,CAAC,GAAGhB,OAAO;EAElC,MAAM;IAAEsE;EAAO,CAAC,GAAG7G,IAAI,CAAC8G,aAAa,CAACxD,OAAO,CAAC;;EAE9C;EACA,IACE,CAACA,OAAO,CAACS,OAAO,IACf8C,MAAM,IACLA,MAAM,KAAK1J,UAAU,CAAC4J,QAAQ,IAC9B,CAACF,MAAM,CAACG,UAAU,CAAC7J,UAAU,CAAC8J,QAAQ,CAAE,EAC1C;IACA,OAAO1E,OAAO;EAChB;;EAEA;EACA;EACA;EACA,MAAM2E,MAAM,GAAG;IAAE,GAAG5D,OAAO,CAACS;EAAQ,CAAC;EACrChD,UAAU,CAACqE,MAAM,CAAC7E,OAAO,CAAE8E,KAAK,IAAK;IACnC,IACEA,KAAK,CAAC5F,IAAI,KAAKpE,aAAa,CAAC8L,eAAe,IAC5C,EAAE9B,KAAK,CAAC1H,IAAI,IAAIuJ,MAAM,CAAC,EACvB;MACAA,MAAM,CAAC7B,KAAK,CAAC1H,IAAI,CAAC,GAAG2H,SAAS;IAChC;EACF,CAAC,CAAC;EAEF,MAAM;IAAEjG,KAAK;IAAEmE;EAAO,CAAC,GAAGzC,UAAU,CAAC9B,QAAQ,CAAC;IAC5C,GAAG8E,OAAO;IACV,GAAGmD;EACL,CAAC,CAAC;;EAEF;EACA,MAAME,SAAS,GAAGpH,IAAI,CAACqH,qBAAqB,CAAC/D,OAAO,EAAEC,KAAK,EAAElE,KAAK,CAAC;EAEnE,OAAO;IACL,GAAGkD,OAAO;IACVwB,OAAO,EAAE3G,KAAK,CAAC2G,OAAO,EAAE1E,KAAK,CAAC;IAC9BkE,KAAK,EAAEnG,KAAK,CAACmG,KAAK,EAAE6D,SAAS,CAAC;IAC9B5D;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA,SAASoB,iBAAiBA,CACxBtB,OAA2B,EAC3BtD,IAAyB,EACzBuC,OAAoB,EACP;EACb,MAAM;IAAEiB,MAAM,GAAG,EAAE;IAAEvC,aAAa;IAAE6C;EAAc,CAAC,GAAGvB,OAAO;;EAE7D;EACA,MAAM+E,aAAa,GAAGrG,aAAa,CAACd,MAAM,CACvCoH,YAAY,IAAKA,YAAY,KAAKvH,IACrC,CAAC;;EAED;EACA,MAAM;IAAEb;EAAM,CAAC,GAAGa,IAAI,CAACwH,KAAK,CACzBxG,kBAAkB,CAACsG,aAAa,CAAC,CACjCrI,QAAQ,CAAC6E,aAAa,EAAE;IAAE,GAAG7G,IAAI;IAAEwK,YAAY,EAAE;EAAK,CAAC,CAAC;;EAE3D;EACA,IAAItI,KAAK,EAAE;IACT,MAAMuI,WAAW,GAAGvI,KAAK,CAACwI,OAAO,CAAC5H,GAAG,CAACnD,QAAQ,CAAC;IAC/C,OAAO;MAAE,GAAG2F,OAAO;MAAEiB,MAAM,EAAEA,MAAM,CAACpC,MAAM,CAACsG,WAAW;IAAE,CAAC;EAC3D;EAEA,OAAOnF,OAAO;AAChB;AAEA,SAAS6B,kBAAkBA,CAACb,KAA0B,EAAU;EAC9D,IACE,CAACA,KAAK,CAACqE,mBAAmB,IAC1B,OAAOrE,KAAK,CAACqE,mBAAmB,KAAK,QAAQ,EAC7C;IACA,MAAM/H,KAAK,CAAC,0CAA0C,CAAC;EACzD;EAEA,OAAO0D,KAAK,CAACqE,mBAAmB;AAClC","ignoreList":[]}
1
+ {"version":3,"file":"FormModel.js","names":["ComponentType","ConditionsModel","ControllerPath","ControllerType","SchemaVersion","convertConditionWrapperFromV2","formDefinitionSchema","formDefinitionV2Schema","generateConditionAlias","hasComponents","hasComponentsEvenIfNoNext","hasRepeater","isConditionWrapperV2","yesNoListId","yesNoListName","add","format","Parser","joi","logger","hasListFormField","todayAsDateOnly","findPage","getError","getPage","loadFormTranslations","createTranslator","extractBaseTranslations","createFormI18nInstance","createPage","validationOptions","opts","defaultServices","FormAction","merge","FormModel","engine","schemaVersion","def","lists","sections","name","formId","values","basePath","ordnanceSurveyApiKey","conditions","pages","services","i18nInstance","controllers","pageDefMap","listDefMap","listDefIdMap","componentDefMap","componentDefIdMap","pageMap","componentMap","constructor","options","schema","V1","warn","result","validate","abortEarly","error","structuredClone","value","baseTranslations","push","id","title","type","items","text","moreThanOnePaymentQuestion","Error","Map","map","page","path","list","filter","flatMap","components","component","forEach","conditionDef","condition","makeCondition","pageDef","some","controller","Status","collection","language","makeFilteredSchema","relevantPages","object","required","concat","stateSchema","parser","operators","logical","Object","assign","functions","dateForComparison","timePeriod","timeUnit","displayName","expr","toConditionExpression","fn","evaluationState","ctx","toConditionContext","evaluate","context","conditionId","propertyName","V2","defineProperty","get","from","parse","toExpression","getList","nameOrId","find","getSection","section","getFormContext","request","state","errors","translator","query","currentPath","startPath","getStartPath","isForceAccess","relevantState","payload","getFormDataFromState","paths","data","referenceNumber","getReferenceNumber","languages","getAvailableLanguages","validateFormPayload","nextPage","initialiseContext","assignEvaluationState","assignRelevantState","pageStateIsInvalid","getNextPath","validateFormState","assignPaths","emptyState","freeze","getContextValueFromState","key","keys","listFields","fields","field","undefined","YesNoField","hasOptionalItems","item","length","fieldStateIsInvalid","validValues","fieldState","getFormValueFromState","isInvalid","isArray","Array","every","includes","t","href","getComponentById","componentId","getListById","listId","getConditionById","numOfPaymentFields","comp","PaymentField","action","getFormParams","Validate","startsWith","External","update","CheckboxesField","formState","getStateFromValidForm","previousPages","relevantPage","model","stripUnknown","errorsState","details","$$__referenceNumber","metadata","translations","cy","code"],"sources":["../../../../../src/server/plugins/engine/models/FormModel.ts"],"sourcesContent":["import {\n ComponentType,\n ConditionsModel,\n ControllerPath,\n ControllerType,\n SchemaVersion,\n convertConditionWrapperFromV2,\n formDefinitionSchema,\n formDefinitionV2Schema,\n generateConditionAlias,\n hasComponents,\n hasComponentsEvenIfNoNext,\n hasRepeater,\n isConditionWrapperV2,\n yesNoListId,\n yesNoListName,\n type ComponentDef,\n type ConditionWrapper,\n type ConditionWrapperV2,\n type ConditionsModelData,\n type DateUnits,\n type Engine,\n type FormDefinition,\n type List,\n type Page,\n type Section\n} from '@defra/forms-model'\nimport { add, format } from 'date-fns'\nimport { Parser, type Value } from 'expr-eval-fork'\nimport { type i18n } from 'i18next'\nimport joi from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { type ListFormComponent } from '~/src/server/plugins/engine/components/ListFormComponent.js'\nimport {} from '~/src/server/plugins/engine/components/YesNoField.js'\nimport {\n hasListFormField,\n type Component\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { todayAsDateOnly } from '~/src/server/plugins/engine/date-helper.js'\nimport {\n findPage,\n getError,\n getPage\n} from '~/src/server/plugins/engine/helpers.js'\nimport { loadFormTranslations } from '~/src/server/plugins/engine/i18n/createFormTranslator.js'\nimport { createTranslator } from '~/src/server/plugins/engine/i18n/createTranslator.js'\nimport { extractBaseTranslations } from '~/src/server/plugins/engine/i18n/extractBaseTranslations.js'\nimport { createFormI18nInstance } from '~/src/server/plugins/engine/i18n/index.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.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/pages.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 schemaVersion: SchemaVersion\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 formId: string\n values: FormDefinition\n basePath: string\n ordnanceSurveyApiKey?: string\n conditions: Partial<Record<string, ExecutableCondition>>\n pages: PageControllerClass[]\n services: Services\n private readonly i18nInstance: i18n\n\n controllers?: Record<string, typeof PageController>\n pageDefMap: Map<string, Page>\n\n listDefMap: Map<string, List>\n listDefIdMap: Map<string, List>\n\n componentDefMap: Map<string, ComponentDef>\n componentDefIdMap: Map<string, ComponentDef>\n\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n\n constructor(\n def: typeof this.def,\n options: {\n basePath: string\n ordnanceSurveyApiKey?: string\n formId?: string\n },\n services: Services = defaultServices,\n controllers?: Record<string, typeof PageController>\n ) {\n let schema = formDefinitionV2Schema\n\n if (!def.schema || def.schema === SchemaVersion.V1) {\n logger.warn(\n `[DEPRECATION NOTICE] Form \"${def.name}\" constructed with legacy V1 schema. See https://defra.github.io/forms-engine-plugin/schemas/form-definition-schema.html.`\n )\n schema = formDefinitionSchema\n }\n\n const result = schema.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 const baseTranslations = extractBaseTranslations(def)\n this.i18nInstance = createFormI18nInstance(baseTranslations)\n loadFormTranslations(def, this.i18nInstance)\n\n // Add default lists. Yes/No text stored as i18n key constants so they\n // resolve to the user's language at render time via the translator.\n def.lists.push({\n id: def.schema === SchemaVersion.V1 ? yesNoListName : yesNoListId,\n name: '__yesNo',\n title: 'Yes/No',\n type: 'boolean',\n items: [\n {\n id: '02900d42-83d1-4c72-a719-c4e8228952fa',\n text: 'components.yesNoField.yes',\n value: true\n },\n {\n id: 'f39000eb-c51b-4019-8f82-bbda0423f04d',\n text: 'components.yesNoField.no',\n value: false\n }\n ]\n })\n\n this.engine = def.engine\n this.schemaVersion = def.schema ?? SchemaVersion.V1\n this.def = def\n this.lists = def.lists\n this.sections = def.sections\n this.name = def.name ?? ''\n this.formId = options.formId ?? ''\n this.values = result.value\n this.basePath = options.basePath\n this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey\n this.conditions = {}\n this.services = services\n this.controllers = controllers\n\n // Assert that there is only one payment question (if any)\n if (this.moreThanOnePaymentQuestion()) {\n throw new Error(\n 'Invalid form definition: Only one payment question is allowed per form'\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.listDefIdMap = new Map(\n def.lists\n .filter((list) => list.id) // Skip lists without an ID\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n .map((list) => [list.id as string, list])\n )\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 this.componentDefIdMap = new Map(\n def.pages.filter(hasComponents).flatMap((page) =>\n page.components\n .filter((component) => component.id) // Skip components without an ID\n .map((component) => {\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return [component.id as string, component]\n })\n )\n )\n\n def.conditions.forEach((conditionDef) => {\n const condition = this.makeCondition(\n isConditionWrapperV2(conditionDef)\n ? convertConditionWrapperFromV2(conditionDef, this)\n : conditionDef\n )\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: 'pages.confirmation.formSubmitted',\n path: ControllerPath.Status,\n controller: ControllerType.Status\n })\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 /** Returns a scoped translator pair for the given language. */\n createTranslator(language = 'en-GB'): Translator {\n return createTranslator(this.i18nInstance, language)\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 // The time element must be stripped (hence using startOfDay() which has no time element),\n // then formatted as YYYY-MM-DD otherwise we can hit time element and BST issues giving the\n // wrong date to compare against.\n // Do not use .toISOString() to format the date as that introduces BST errors.\n return format(\n add(todayAsDateOnly(), { [timeUnit]: timePeriod }),\n 'yyyy-MM-dd'\n )\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 conditionId in conditions) {\n const propertyName =\n this.schemaVersion === SchemaVersion.V2\n ? generateConditionAlias(conditionId)\n : conditionId\n\n Object.defineProperty(context, propertyName, {\n get() {\n return conditions[conditionId]?.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(nameOrId: string): List | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.lists.find((list) => list.name === nameOrId)\n : this.lists.find((list) => list.id === nameOrId)\n }\n\n getSection(nameOrId: string): Section | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.sections.find((section) => section.name === nameOrId)\n : this.sections.find((section) => section.id === nameOrId)\n }\n\n /**\n * Form context for the current page\n */\n getFormContext(\n request: FormContextRequest,\n state: FormSubmissionState,\n errors?: FormSubmissionError[],\n translator?: Translator\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 referenceNumber: getReferenceNumber(state),\n languages: getAvailableLanguages(this.def),\n translator\n }\n\n // Validate current page\n context = validateFormPayload(request, page, context, translator)\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 (\n this.pageStateIsInvalid(context, nextPage, translator) ||\n nextPage.path === currentPath\n ) {\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 // Initialise `evaluationState` for all keys using empty state.\n // This is because the current condition evaluation library (eval-expr)\n // will throw if an expression uses a key that is undefined.\n const emptyState = Object.freeze({})\n\n for (const page of this.pages) {\n const { collection, pageDef } = page\n\n if (!hasRepeater(pageDef)) {\n Object.assign(\n context.evaluationState,\n collection.getContextValueFromState(emptyState)\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 pageStateIsInvalid(\n context: FormContext,\n page: PageControllerClass,\n translator?: Translator\n ) {\n // Get any list-bound fields on the page\n const listFields = page.collection.fields.filter(hasListFormField)\n\n // For each list field that is bound to a list that contains any conditional items,\n // we need to check any answers are still valid. Do this by evaluating the conditions\n // and ensuring any current answers are all included in the set of valid answers\n for (const field of listFields) {\n const list = field.list\n\n // Filter out YesNo as they can't be conditional\n if (list !== undefined && field.type !== ComponentType.YesNoField) {\n const hasOptionalItems =\n list.items.filter((item) => item.condition).length > 0\n\n if (hasOptionalItems) {\n return this.fieldStateIsInvalid(context, field, list, translator)\n }\n }\n }\n }\n\n private fieldStateIsInvalid(\n context: FormContext,\n field: ListFormComponent,\n list: List,\n translator?: Translator\n ) {\n const { evaluationState, state } = context\n\n const validValues = list.items\n .filter((item) =>\n item.condition\n ? this.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n .map((item) => item.value)\n\n // Get the field state\n const fieldState = field.getFormValueFromState(state)\n\n if (fieldState !== undefined) {\n let isInvalid = false\n const isArray = Array.isArray(fieldState)\n\n // Check if any saved state value(s) are still valid\n // and return true if any are invalid\n if (isArray) {\n isInvalid = !fieldState.every((item) => validValues.includes(item))\n } else {\n isInvalid = !validValues.includes(fieldState)\n }\n\n if (isInvalid) {\n context.errors ??= []\n\n const text = (translator ?? this.createTranslator('en-GB')).t(\n 'errors.optionsMismatch'\n )\n\n context.errors.push({\n text,\n name: field.name,\n href: `#${field.name}`,\n path: [`#${field.name}`]\n })\n }\n\n return isInvalid\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 getComponentById(componentId: string): ComponentDef | undefined {\n return this.componentDefIdMap.get(componentId)\n }\n\n getListById(listId: string): List | undefined {\n return this.listDefIdMap.get(listId)\n }\n\n /**\n * Returns a condition by its ID. O(n) lookup time.\n * @param conditionId\n * @returns\n */\n getConditionById(conditionId: string): ConditionWrapperV2 | undefined {\n return this.def.conditions\n .filter(isConditionWrapperV2)\n .find((condition) => condition.id === conditionId)\n }\n\n /**\n * Checks that only one payment field exists (if any payments fields exist)\n */\n moreThanOnePaymentQuestion() {\n const numOfPaymentFields = this.def.pages\n .flatMap((page) =>\n hasComponentsEvenIfNoNext(page) ? page.components : []\n )\n .filter((comp) => comp.type === ComponentType.PaymentField).length\n return numOfPaymentFields > 1\n }\n}\n\n/**\n * Validate current page only\n */\nfunction validateFormPayload(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator?: Translator\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 (\n !request.payload ||\n (action &&\n action !== FormAction.Validate &&\n !action.startsWith(FormAction.External))\n ) {\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, ...update },\n translator\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\nfunction getReferenceNumber(state: FormSubmissionState): string {\n if (\n !state.$$__referenceNumber ||\n typeof state.$$__referenceNumber !== 'string'\n ) {\n throw Error('Reference number not found in form state')\n }\n\n return state.$$__referenceNumber\n}\n\nexport function getAvailableLanguages(\n def: FormDefinition\n): { name: string; code: string }[] {\n // @ts-expect-error - dynamic property\n if (def.metadata?.translations?.cy) {\n return [\n { name: 'English', code: 'en-GB' },\n { name: 'Cymraeg', code: 'cy' }\n ]\n }\n return []\n}\n"],"mappings":"AAAA,SACEA,aAAa,EACbC,eAAe,EACfC,cAAc,EACdC,cAAc,EACdC,aAAa,EACbC,6BAA6B,EAC7BC,oBAAoB,EACpBC,sBAAsB,EACtBC,sBAAsB,EACtBC,aAAa,EACbC,yBAAyB,EACzBC,WAAW,EACXC,oBAAoB,EACpBC,WAAW,EACXC,aAAa,QAWR,oBAAoB;AAC3B,SAASC,GAAG,EAAEC,MAAM,QAAQ,UAAU;AACtC,SAASC,MAAM,QAAoB,gBAAgB;AAEnD,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,MAAM;AAEf;AACA,SACEC,gBAAgB;AAGlB,SAASC,eAAe;AACxB,SACEC,QAAQ,EACRC,QAAQ,EACRC,OAAO;AAET,SAASC,oBAAoB;AAC7B,SAASC,gBAAgB;AACzB,SAASC,uBAAuB;AAChC,SAASC,sBAAsB;AAI/B,SACEC,UAAU;AAGZ,SAASC,iBAAiB,IAAIC,IAAI;AAClC,OAAO,KAAKC,eAAe;AAQ3B,SAASC,UAAU;AACnB,SAASC,KAAK;AAGd,OAAO,MAAMC,SAAS,CAAC;EACrB;EACAC,MAAM;EAENC,aAAa;;EAEb;EACAC,GAAG;EAEHC,KAAK;EACLC,QAAQ,GAA+B,EAAE;EACzCC,IAAI;EACJC,MAAM;EACNC,MAAM;EACNC,QAAQ;EACRC,oBAAoB;EACpBC,UAAU;EACVC,KAAK;EACLC,QAAQ;EACSC,YAAY;EAE7BC,WAAW;EACXC,UAAU;EAEVC,UAAU;EACVC,YAAY;EAEZC,eAAe;EACfC,iBAAiB;EAEjBC,OAAO;EACPC,YAAY;EAEZC,WAAWA,CACTpB,GAAoB,EACpBqB,OAIC,EACDX,QAAkB,GAAGhB,eAAe,EACpCkB,WAAmD,EACnD;IACA,IAAIU,MAAM,GAAGrD,sBAAsB;IAEnC,IAAI,CAAC+B,GAAG,CAACsB,MAAM,IAAItB,GAAG,CAACsB,MAAM,KAAKxD,aAAa,CAACyD,EAAE,EAAE;MAClD1C,MAAM,CAAC2C,IAAI,CACT,8BAA8BxB,GAAG,CAACG,IAAI,2HACxC,CAAC;MACDmB,MAAM,GAAGtD,oBAAoB;IAC/B;IAEA,MAAMyD,MAAM,GAAGH,MAAM,CAACI,QAAQ,CAAC1B,GAAG,EAAE;MAAE2B,UAAU,EAAE;IAAM,CAAC,CAAC;IAE1D,IAAIF,MAAM,CAACG,KAAK,EAAE;MAChB,MAAMH,MAAM,CAACG,KAAK;IACpB;;IAEA;IACA;IACA5B,GAAG,GAAG6B,eAAe,CAACJ,MAAM,CAACK,KAAK,CAAC;IAEnC,MAAMC,gBAAgB,GAAG1C,uBAAuB,CAACW,GAAG,CAAC;IACrD,IAAI,CAACW,YAAY,GAAGrB,sBAAsB,CAACyC,gBAAgB,CAAC;IAC5D5C,oBAAoB,CAACa,GAAG,EAAE,IAAI,CAACW,YAAY,CAAC;;IAE5C;IACA;IACAX,GAAG,CAACC,KAAK,CAAC+B,IAAI,CAAC;MACbC,EAAE,EAAEjC,GAAG,CAACsB,MAAM,KAAKxD,aAAa,CAACyD,EAAE,GAAG/C,aAAa,GAAGD,WAAW;MACjE4B,IAAI,EAAE,SAAS;MACf+B,KAAK,EAAE,QAAQ;MACfC,IAAI,EAAE,SAAS;MACfC,KAAK,EAAE,CACL;QACEH,EAAE,EAAE,sCAAsC;QAC1CI,IAAI,EAAE,2BAA2B;QACjCP,KAAK,EAAE;MACT,CAAC,EACD;QACEG,EAAE,EAAE,sCAAsC;QAC1CI,IAAI,EAAE,0BAA0B;QAChCP,KAAK,EAAE;MACT,CAAC;IAEL,CAAC,CAAC;IAEF,IAAI,CAAChC,MAAM,GAAGE,GAAG,CAACF,MAAM;IACxB,IAAI,CAACC,aAAa,GAAGC,GAAG,CAACsB,MAAM,IAAIxD,aAAa,CAACyD,EAAE;IACnD,IAAI,CAACvB,GAAG,GAAGA,GAAG;IACd,IAAI,CAACC,KAAK,GAAGD,GAAG,CAACC,KAAK;IACtB,IAAI,CAACC,QAAQ,GAAGF,GAAG,CAACE,QAAQ;IAC5B,IAAI,CAACC,IAAI,GAAGH,GAAG,CAACG,IAAI,IAAI,EAAE;IAC1B,IAAI,CAACC,MAAM,GAAGiB,OAAO,CAACjB,MAAM,IAAI,EAAE;IAClC,IAAI,CAACC,MAAM,GAAGoB,MAAM,CAACK,KAAK;IAC1B,IAAI,CAACxB,QAAQ,GAAGe,OAAO,CAACf,QAAQ;IAChC,IAAI,CAACC,oBAAoB,GAAGc,OAAO,CAACd,oBAAoB;IACxD,IAAI,CAACC,UAAU,GAAG,CAAC,CAAC;IACpB,IAAI,CAACE,QAAQ,GAAGA,QAAQ;IACxB,IAAI,CAACE,WAAW,GAAGA,WAAW;;IAE9B;IACA,IAAI,IAAI,CAAC0B,0BAA0B,CAAC,CAAC,EAAE;MACrC,MAAM,IAAIC,KAAK,CACb,wEACF,CAAC;IACH;IAEA,IAAI,CAAC1B,UAAU,GAAG,IAAI2B,GAAG,CAACxC,GAAG,CAACS,KAAK,CAACgC,GAAG,CAAEC,IAAI,IAAK,CAACA,IAAI,CAACC,IAAI,EAAED,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC5B,UAAU,GAAG,IAAI0B,GAAG,CAACxC,GAAG,CAACC,KAAK,CAACwC,GAAG,CAAEG,IAAI,IAAK,CAACA,IAAI,CAACzC,IAAI,EAAEyC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC7B,YAAY,GAAG,IAAIyB,GAAG,CACzBxC,GAAG,CAACC,KAAK,CACN4C,MAAM,CAAED,IAAI,IAAKA,IAAI,CAACX,EAAE,CAAC,CAAC;IAC3B;IAAA,CACCQ,GAAG,CAAEG,IAAI,IAAK,CAACA,IAAI,CAACX,EAAE,EAAYW,IAAI,CAAC,CAC5C,CAAC;IACD,IAAI,CAAC5B,eAAe,GAAG,IAAIwB,GAAG,CAC5BxC,GAAG,CAACS,KAAK,CACNoC,MAAM,CAAC1E,aAAa,CAAC,CACrB2E,OAAO,CAAEJ,IAAI,IACZA,IAAI,CAACK,UAAU,CAACN,GAAG,CAAEO,SAAS,IAAK,CAACA,SAAS,CAAC7C,IAAI,EAAE6C,SAAS,CAAC,CAChE,CACJ,CAAC;IACD,IAAI,CAAC/B,iBAAiB,GAAG,IAAIuB,GAAG,CAC9BxC,GAAG,CAACS,KAAK,CAACoC,MAAM,CAAC1E,aAAa,CAAC,CAAC2E,OAAO,CAAEJ,IAAI,IAC3CA,IAAI,CAACK,UAAU,CACZF,MAAM,CAAEG,SAAS,IAAKA,SAAS,CAACf,EAAE,CAAC,CAAC;IAAA,CACpCQ,GAAG,CAAEO,SAAS,IAAK;MAClB;MACA,OAAO,CAACA,SAAS,CAACf,EAAE,EAAYe,SAAS,CAAC;IAC5C,CAAC,CACL,CACF,CAAC;IAEDhD,GAAG,CAACQ,UAAU,CAACyC,OAAO,CAAEC,YAAY,IAAK;MACvC,MAAMC,SAAS,GAAG,IAAI,CAACC,aAAa,CAClC9E,oBAAoB,CAAC4E,YAAY,CAAC,GAC9BnF,6BAA6B,CAACmF,YAAY,EAAE,IAAI,CAAC,GACjDA,YACN,CAAC;MACD,IAAI,CAAC1C,UAAU,CAAC2C,SAAS,CAAChD,IAAI,CAAC,GAAGgD,SAAS;IAC7C,CAAC,CAAC;IAEF,IAAI,CAAC1C,KAAK,GAAGT,GAAG,CAACS,KAAK,CAACgC,GAAG,CAAEY,OAAO,IAAK9D,UAAU,CAAC,IAAI,EAAE8D,OAAO,CAAC,CAAC;IAElE,IACE,CAACrD,GAAG,CAACS,KAAK,CAAC6C,IAAI,CACb,CAAC;MAAEC;IAAW,CAAC;IACb;IACAA,UAAU,KAAK1F,cAAc,CAAC2F,MAClC,CAAC,EACD;MACA,IAAI,CAAC/C,KAAK,CAACuB,IAAI,CACbzC,UAAU,CAAC,IAAI,EAAE;QACf2C,KAAK,EAAE,kCAAkC;QACzCS,IAAI,EAAE/E,cAAc,CAAC4F,MAAM;QAC3BD,UAAU,EAAE1F,cAAc,CAAC2F;MAC7B,CAAC,CACH,CAAC;IACH;IAEA,IAAI,CAACtC,OAAO,GAAG,IAAIsB,GAAG,CAAC,IAAI,CAAC/B,KAAK,CAACgC,GAAG,CAAEC,IAAI,IAAK,CAACA,IAAI,CAACC,IAAI,EAAED,IAAI,CAAC,CAAC,CAAC;IACnE,IAAI,CAACvB,YAAY,GAAG,IAAIqB,GAAG,CACzB,IAAI,CAAC/B,KAAK,CAACqC,OAAO,CAAEJ,IAAI,IACtBA,IAAI,CAACe,UAAU,CAACV,UAAU,CAACN,GAAG,CAAEO,SAAS,IAAK,CAC5CA,SAAS,CAAC7C,IAAI,EACd6C,SAAS,CACV,CACH,CACF,CAAC;EACH;;EAEA;EACA5D,gBAAgBA,CAACsE,QAAQ,GAAG,OAAO,EAAc;IAC/C,OAAOtE,gBAAgB,CAAC,IAAI,CAACuB,YAAY,EAAE+C,QAAQ,CAAC;EACtD;;EAEA;AACF;AACA;AACA;EACEC,kBAAkBA,CAACC,aAAoC,EAAE;IACvD;IACA;IACA,IAAItC,MAAM,GAAG1C,GAAG,CAACiF,MAAM,CAAsB,CAAC,CAACC,QAAQ,CAAC,CAAC;IAEzDF,aAAa,CAACX,OAAO,CAAEP,IAAI,IAAK;MAC9BpB,MAAM,GAAGA,MAAM,CAACyC,MAAM,CAACrB,IAAI,CAACe,UAAU,CAACO,WAAW,CAAC;IACrD,CAAC,CAAC;IAEF,OAAO1C,MAAM;EACf;;EAEA;AACF;AACA;AACA;EACE8B,aAAaA,CAACD,SAA2B,EAAuB;IAC9D,MAAMc,MAAM,GAAG,IAAItF,MAAM,CAAC;MACxBuF,SAAS,EAAE;QACTC,OAAO,EAAE;MACX;IACF,CAAC,CAAC;IAEFC,MAAM,CAACC,MAAM,CAACJ,MAAM,CAACK,SAAS,EAAE;MAC9BC,iBAAiBA,CAACC,UAAkB,EAAEC,QAAmB,EAAE;QACzD;QACA;QACA;QACA;QACA,OAAO/F,MAAM,CACXD,GAAG,CAACM,eAAe,CAAC,CAAC,EAAE;UAAE,CAAC0F,QAAQ,GAAGD;QAAW,CAAC,CAAC,EAClD,YACF,CAAC;MACH;IACF,CAAC,CAAC;IAEF,MAAM;MAAErE,IAAI;MAAEuE,WAAW;MAAE5C;IAAM,CAAC,GAAGqB,SAAS;IAC9C,MAAMwB,IAAI,GAAG,IAAI,CAACC,qBAAqB,CAAC9C,KAAK,EAAEmC,MAAM,CAAC;IAEtD,MAAMY,EAAE,GAAIC,eAA0B,IAAK;MACzC,MAAMC,GAAG,GAAG,IAAI,CAACC,kBAAkB,CAACF,eAAe,EAAE,IAAI,CAACtE,UAAU,CAAC;MACrE,IAAI;QACF,OAAOmE,IAAI,CAACM,QAAQ,CAACF,GAAG,CAAC;MAC3B,CAAC,CAAC,MAAM;QACN,OAAO,KAAK;MACd;IACF,CAAC;IAED,OAAO;MACL5E,IAAI;MACJuE,WAAW;MACX5C,KAAK;MACL6C,IAAI;MACJE;IACF,CAAC;EACH;EAEAG,kBAAkBA,CAChBF,eAA0B,EAC1BtE,UAAwD,EACxD;IACA,MAAM0E,OAAO,GAAG;MAAE,GAAGJ;IAAgB,CAAC;IAEtC,KAAK,MAAMK,WAAW,IAAI3E,UAAU,EAAE;MACpC,MAAM4E,YAAY,GAChB,IAAI,CAACrF,aAAa,KAAKjC,aAAa,CAACuH,EAAE,GACnCnH,sBAAsB,CAACiH,WAAW,CAAC,GACnCA,WAAW;MAEjBf,MAAM,CAACkB,cAAc,CAACJ,OAAO,EAAEE,YAAY,EAAE;QAC3CG,GAAGA,CAAA,EAAG;UACJ,OAAO/E,UAAU,CAAC2E,WAAW,CAAC,EAAEN,EAAE,CAACC,eAAe,CAAC;QACrD;MACF,CAAC,CAAC;IACJ;IAEA,OAAOI,OAAO;EAChB;EAEAN,qBAAqBA,CAAC9C,KAA0B,EAAEmC,MAAc,EAAE;IAChE,MAAMzD,UAAU,GAAG7C,eAAe,CAAC6H,IAAI,CAAC1D,KAAK,CAAC;IAC9C,OAAOmC,MAAM,CAACwB,KAAK,CAACjF,UAAU,CAACkF,YAAY,CAAC,CAAC,CAAC;EAChD;EAEAC,OAAOA,CAACC,QAAgB,EAAoB;IAC1C,OAAO,IAAI,CAAC7F,aAAa,KAAKjC,aAAa,CAACyD,EAAE,GAC1C,IAAI,CAACtB,KAAK,CAAC4F,IAAI,CAAEjD,IAAI,IAAKA,IAAI,CAACzC,IAAI,KAAKyF,QAAQ,CAAC,GACjD,IAAI,CAAC3F,KAAK,CAAC4F,IAAI,CAAEjD,IAAI,IAAKA,IAAI,CAACX,EAAE,KAAK2D,QAAQ,CAAC;EACrD;EAEAE,UAAUA,CAACF,QAAgB,EAAuB;IAChD,OAAO,IAAI,CAAC7F,aAAa,KAAKjC,aAAa,CAACyD,EAAE,GAC1C,IAAI,CAACrB,QAAQ,CAAC2F,IAAI,CAAEE,OAAO,IAAKA,OAAO,CAAC5F,IAAI,KAAKyF,QAAQ,CAAC,GAC1D,IAAI,CAAC1F,QAAQ,CAAC2F,IAAI,CAAEE,OAAO,IAAKA,OAAO,CAAC9D,EAAE,KAAK2D,QAAQ,CAAC;EAC9D;;EAEA;AACF;AACA;EACEI,cAAcA,CACZC,OAA2B,EAC3BC,KAA0B,EAC1BC,MAA8B,EAC9BC,UAAuB,EACV;IACb,MAAM;MAAEC;IAAM,CAAC,GAAGJ,OAAO;IAEzB,MAAMvD,IAAI,GAAGxD,OAAO,CAAC,IAAI,EAAE+G,OAAO,CAAC;;IAEnC;IACA,MAAMK,WAAW,GAAG5D,IAAI,CAACC,IAAI;IAC7B,MAAM4D,SAAS,GAAG7D,IAAI,CAAC8D,YAAY,CAAC,CAAC;;IAErC;IACA,MAAMC,aAAa,GAAG,OAAO,IAAIJ,KAAK;IAEtC,IAAInB,OAAoB,GAAG;MACzBJ,eAAe,EAAE,CAAC,CAAC;MACnB4B,aAAa,EAAE,CAAC,CAAC;MACjB9C,aAAa,EAAE,EAAE;MACjB+C,OAAO,EAAEjE,IAAI,CAACkE,oBAAoB,CAACX,OAAO,EAAEC,KAAK,CAAC;MAClDA,KAAK;MACLW,KAAK,EAAE,EAAE;MACTV,MAAM;MACNM,aAAa;MACbK,IAAI,EAAE,CAAC,CAAC;MACRjG,UAAU,EAAE,IAAI,CAACA,UAAU;MAC3BC,UAAU,EAAE,IAAI,CAACA,UAAU;MAC3BE,eAAe,EAAE,IAAI,CAACA,eAAe;MACrCE,OAAO,EAAE,IAAI,CAACA,OAAO;MACrBC,YAAY,EAAE,IAAI,CAACA,YAAY;MAC/B4F,eAAe,EAAEC,kBAAkB,CAACd,KAAK,CAAC;MAC1Ce,SAAS,EAAEC,qBAAqB,CAAC,IAAI,CAAClH,GAAG,CAAC;MAC1CoG;IACF,CAAC;;IAED;IACAlB,OAAO,GAAGiC,mBAAmB,CAAClB,OAAO,EAAEvD,IAAI,EAAEwC,OAAO,EAAEkB,UAAU,CAAC;;IAEjE;IACA,IAAIgB,QAAQ,GAAGpI,QAAQ,CAAC,IAAI,EAAEuH,SAAS,CAAC;IAExC,IAAI,CAACc,iBAAiB,CAACnC,OAAO,CAAC;;IAE/B;IACA,OAAOkC,QAAQ,EAAE;MACf;MACAlC,OAAO,CAACtB,aAAa,CAAC5B,IAAI,CAACoF,QAAQ,CAAC;MAEpC,IAAI,CAACE,qBAAqB,CAACpC,OAAO,EAAEkC,QAAQ,CAAC;MAE7C,IAAI,CAACG,mBAAmB,CAACrC,OAAO,EAAEkC,QAAQ,CAAC;;MAE3C;MACA,IACE,IAAI,CAACI,kBAAkB,CAACtC,OAAO,EAAEkC,QAAQ,EAAEhB,UAAU,CAAC,IACtDgB,QAAQ,CAACzE,IAAI,KAAK2D,WAAW,EAC7B;QACA;MACF;;MAEA;MACAc,QAAQ,GAAGpI,QAAQ,CAAC,IAAI,EAAEoI,QAAQ,CAACK,WAAW,CAACvC,OAAO,CAAC,CAAC;IAC1D;;IAEA;IACAA,OAAO,GAAGwC,iBAAiB,CAACzB,OAAO,EAAEvD,IAAI,EAAEwC,OAAO,CAAC;;IAEnD;IACA,IAAI,CAACyC,WAAW,CAACzC,OAAO,CAAC;IAEzB,OAAOA,OAAO;EAChB;EAEQmC,iBAAiBA,CAACnC,OAAoB,EAAE;IAC9C;IACA;IACA;IACA,MAAM0C,UAAU,GAAGxD,MAAM,CAACyD,MAAM,CAAC,CAAC,CAAC,CAAC;IAEpC,KAAK,MAAMnF,IAAI,IAAI,IAAI,CAACjC,KAAK,EAAE;MAC7B,MAAM;QAAEgD,UAAU;QAAEJ;MAAQ,CAAC,GAAGX,IAAI;MAEpC,IAAI,CAACrE,WAAW,CAACgF,OAAO,CAAC,EAAE;QACzBe,MAAM,CAACC,MAAM,CACXa,OAAO,CAACJ,eAAe,EACvBrB,UAAU,CAACqE,wBAAwB,CAACF,UAAU,CAChD,CAAC;MACH;IACF;EACF;EAEQN,qBAAqBA,CAC3BpC,OAAoB,EACpBxC,IAAyB,EACzB;IACA,MAAM;MAAEe,UAAU;MAAEJ;IAAQ,CAAC,GAAGX,IAAI;IACpC;;IAEA,IAAI,CAACrE,WAAW,CAACgF,OAAO,CAAC,EAAE;MACzBe,MAAM,CAACC,MAAM,CACXa,OAAO,CAACJ,eAAe,EACvBrB,UAAU,CAACqE,wBAAwB,CAAC5C,OAAO,CAACgB,KAAK,CACnD,CAAC;IACH;EACF;EAEQqB,mBAAmBA,CAACrC,OAAoB,EAAExC,IAAyB,EAAE;IAC3E;IACA,KAAK,MAAMqF,GAAG,IAAIrF,IAAI,CAACsF,IAAI,EAAE;MAC3B,IAAI,OAAO9C,OAAO,CAACgB,KAAK,CAAC6B,GAAG,CAAC,KAAK,WAAW,EAAE;QAC7C7C,OAAO,CAACwB,aAAa,CAACqB,GAAG,CAAC,GAAG7C,OAAO,CAACgB,KAAK,CAAC6B,GAAG,CAAC;MACjD;IACF;EACF;EAEQP,kBAAkBA,CACxBtC,OAAoB,EACpBxC,IAAyB,EACzB0D,UAAuB,EACvB;IACA;IACA,MAAM6B,UAAU,GAAGvF,IAAI,CAACe,UAAU,CAACyE,MAAM,CAACrF,MAAM,CAAC/D,gBAAgB,CAAC;;IAElE;IACA;IACA;IACA,KAAK,MAAMqJ,KAAK,IAAIF,UAAU,EAAE;MAC9B,MAAMrF,IAAI,GAAGuF,KAAK,CAACvF,IAAI;;MAEvB;MACA,IAAIA,IAAI,KAAKwF,SAAS,IAAID,KAAK,CAAChG,IAAI,KAAKzE,aAAa,CAAC2K,UAAU,EAAE;QACjE,MAAMC,gBAAgB,GACpB1F,IAAI,CAACR,KAAK,CAACS,MAAM,CAAE0F,IAAI,IAAKA,IAAI,CAACpF,SAAS,CAAC,CAACqF,MAAM,GAAG,CAAC;QAExD,IAAIF,gBAAgB,EAAE;UACpB,OAAO,IAAI,CAACG,mBAAmB,CAACvD,OAAO,EAAEiD,KAAK,EAAEvF,IAAI,EAAEwD,UAAU,CAAC;QACnE;MACF;IACF;EACF;EAEQqC,mBAAmBA,CACzBvD,OAAoB,EACpBiD,KAAwB,EACxBvF,IAAU,EACVwD,UAAuB,EACvB;IACA,MAAM;MAAEtB,eAAe;MAAEoB;IAAM,CAAC,GAAGhB,OAAO;IAE1C,MAAMwD,WAAW,GAAG9F,IAAI,CAACR,KAAK,CAC3BS,MAAM,CAAE0F,IAAI,IACXA,IAAI,CAACpF,SAAS,GACV,IAAI,CAAC3C,UAAU,CAAC+H,IAAI,CAACpF,SAAS,CAAC,EAAE0B,EAAE,CAACC,eAAe,CAAC,GACpD,IACN,CAAC,CACArC,GAAG,CAAE8F,IAAI,IAAKA,IAAI,CAACzG,KAAK,CAAC;;IAE5B;IACA,MAAM6G,UAAU,GAAGR,KAAK,CAACS,qBAAqB,CAAC1C,KAAK,CAAC;IAErD,IAAIyC,UAAU,KAAKP,SAAS,EAAE;MAC5B,IAAIS,SAAS,GAAG,KAAK;MACrB,MAAMC,OAAO,GAAGC,KAAK,CAACD,OAAO,CAACH,UAAU,CAAC;;MAEzC;MACA;MACA,IAAIG,OAAO,EAAE;QACXD,SAAS,GAAG,CAACF,UAAU,CAACK,KAAK,CAAET,IAAI,IAAKG,WAAW,CAACO,QAAQ,CAACV,IAAI,CAAC,CAAC;MACrE,CAAC,MAAM;QACLM,SAAS,GAAG,CAACH,WAAW,CAACO,QAAQ,CAACN,UAAU,CAAC;MAC/C;MAEA,IAAIE,SAAS,EAAE;QACb3D,OAAO,CAACiB,MAAM,KAAK,EAAE;QAErB,MAAM9D,IAAI,GAAG,CAAC+D,UAAU,IAAI,IAAI,CAAChH,gBAAgB,CAAC,OAAO,CAAC,EAAE8J,CAAC,CAC3D,wBACF,CAAC;QAEDhE,OAAO,CAACiB,MAAM,CAACnE,IAAI,CAAC;UAClBK,IAAI;UACJlC,IAAI,EAAEgI,KAAK,CAAChI,IAAI;UAChBgJ,IAAI,EAAE,IAAIhB,KAAK,CAAChI,IAAI,EAAE;UACtBwC,IAAI,EAAE,CAAC,IAAIwF,KAAK,CAAChI,IAAI,EAAE;QACzB,CAAC,CAAC;MACJ;MAEA,OAAO0I,SAAS;IAClB;EACF;EAEQlB,WAAWA,CAACzC,OAAoB,EAAE;IACxC,KAAK,MAAM;MAAE8C,IAAI;MAAErF;IAAK,CAAC,IAAIuC,OAAO,CAACtB,aAAa,EAAE;MAClDsB,OAAO,CAAC2B,KAAK,CAAC7E,IAAI,CAACW,IAAI,CAAC;;MAExB;MACA,IACEuC,OAAO,CAACiB,MAAM,EAAE7C,IAAI,CAAC,CAAC;QAAEnD,IAAI;QAAEwC;MAAK,CAAC,KAAK;QACvC,OAAOqF,IAAI,CAACiB,QAAQ,CAAC9I,IAAI,CAAC,IAAI6H,IAAI,CAAC1E,IAAI,CAAEyE,GAAG,IAAKpF,IAAI,CAACsG,QAAQ,CAAClB,GAAG,CAAC,CAAC;MACtE,CAAC,CAAC,EACF;QACA;MACF;IACF;EACF;EAEAqB,gBAAgBA,CAACC,WAAmB,EAA4B;IAC9D,OAAO,IAAI,CAACpI,iBAAiB,CAACsE,GAAG,CAAC8D,WAAW,CAAC;EAChD;EAEAC,WAAWA,CAACC,MAAc,EAAoB;IAC5C,OAAO,IAAI,CAACxI,YAAY,CAACwE,GAAG,CAACgE,MAAM,CAAC;EACtC;;EAEA;AACF;AACA;AACA;AACA;EACEC,gBAAgBA,CAACrE,WAAmB,EAAkC;IACpE,OAAO,IAAI,CAACnF,GAAG,CAACQ,UAAU,CACvBqC,MAAM,CAACvE,oBAAoB,CAAC,CAC5BuH,IAAI,CAAE1C,SAAS,IAAKA,SAAS,CAAClB,EAAE,KAAKkD,WAAW,CAAC;EACtD;;EAEA;AACF;AACA;EACE7C,0BAA0BA,CAAA,EAAG;IAC3B,MAAMmH,kBAAkB,GAAG,IAAI,CAACzJ,GAAG,CAACS,KAAK,CACtCqC,OAAO,CAAEJ,IAAI,IACZtE,yBAAyB,CAACsE,IAAI,CAAC,GAAGA,IAAI,CAACK,UAAU,GAAG,EACtD,CAAC,CACAF,MAAM,CAAE6G,IAAI,IAAKA,IAAI,CAACvH,IAAI,KAAKzE,aAAa,CAACiM,YAAY,CAAC,CAACnB,MAAM;IACpE,OAAOiB,kBAAkB,GAAG,CAAC;EAC/B;AACF;;AAEA;AACA;AACA;AACA,SAAStC,mBAAmBA,CAC1BlB,OAA2B,EAC3BvD,IAAyB,EACzBwC,OAAoB,EACpBkB,UAAuB,EACV;EACb,MAAM;IAAE3C;EAAW,CAAC,GAAGf,IAAI;EAC3B,MAAM;IAAEiE,OAAO;IAAET;EAAM,CAAC,GAAGhB,OAAO;EAElC,MAAM;IAAE0E;EAAO,CAAC,GAAGlH,IAAI,CAACmH,aAAa,CAAC5D,OAAO,CAAC;;EAE9C;EACA,IACE,CAACA,OAAO,CAACU,OAAO,IACfiD,MAAM,IACLA,MAAM,KAAKjK,UAAU,CAACmK,QAAQ,IAC9B,CAACF,MAAM,CAACG,UAAU,CAACpK,UAAU,CAACqK,QAAQ,CAAE,EAC1C;IACA,OAAO9E,OAAO;EAChB;;EAEA;EACA;EACA;EACA,MAAM+E,MAAM,GAAG;IAAE,GAAGhE,OAAO,CAACU;EAAQ,CAAC;EACrClD,UAAU,CAACyE,MAAM,CAACjF,OAAO,CAAEkF,KAAK,IAAK;IACnC,IACEA,KAAK,CAAChG,IAAI,KAAKzE,aAAa,CAACwM,eAAe,IAC5C,EAAE/B,KAAK,CAAChI,IAAI,IAAI8J,MAAM,CAAC,EACvB;MACAA,MAAM,CAAC9B,KAAK,CAAChI,IAAI,CAAC,GAAGiI,SAAS;IAChC;EACF,CAAC,CAAC;EAEF,MAAM;IAAEtG,KAAK;IAAEqE;EAAO,CAAC,GAAG1C,UAAU,CAAC/B,QAAQ,CAC3C;IAAE,GAAGiF,OAAO;IAAE,GAAGsD;EAAO,CAAC,EACzB7D,UACF,CAAC;;EAED;EACA,MAAM+D,SAAS,GAAGzH,IAAI,CAAC0H,qBAAqB,CAACnE,OAAO,EAAEC,KAAK,EAAEpE,KAAK,CAAC;EAEnE,OAAO;IACL,GAAGoD,OAAO;IACVyB,OAAO,EAAE/G,KAAK,CAAC+G,OAAO,EAAE7E,KAAK,CAAC;IAC9BoE,KAAK,EAAEtG,KAAK,CAACsG,KAAK,EAAEiE,SAAS,CAAC;IAC9BhE;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA,SAASuB,iBAAiBA,CACxBzB,OAA2B,EAC3BvD,IAAyB,EACzBwC,OAAoB,EACP;EACb,MAAM;IAAEiB,MAAM,GAAG,EAAE;IAAEvC,aAAa;IAAE8C;EAAc,CAAC,GAAGxB,OAAO;;EAE7D;EACA,MAAMmF,aAAa,GAAGzG,aAAa,CAACf,MAAM,CACvCyH,YAAY,IAAKA,YAAY,KAAK5H,IACrC,CAAC;;EAED;EACA,MAAM;IAAEd;EAAM,CAAC,GAAGc,IAAI,CAAC6H,KAAK,CACzB5G,kBAAkB,CAAC0G,aAAa,CAAC,CACjC3I,QAAQ,CAACgF,aAAa,EAAE;IAAE,GAAGjH,IAAI;IAAE+K,YAAY,EAAE;EAAK,CAAC,CAAC;;EAE3D;EACA,IAAI5I,KAAK,EAAE;IACT,MAAM6I,WAAW,GAAG7I,KAAK,CAAC8I,OAAO,CAACjI,GAAG,CAACxD,QAAQ,CAAC;IAC/C,OAAO;MAAE,GAAGiG,OAAO;MAAEiB,MAAM,EAAEA,MAAM,CAACpC,MAAM,CAAC0G,WAAW;IAAE,CAAC;EAC3D;EAEA,OAAOvF,OAAO;AAChB;AAEA,SAAS8B,kBAAkBA,CAACd,KAA0B,EAAU;EAC9D,IACE,CAACA,KAAK,CAACyE,mBAAmB,IAC1B,OAAOzE,KAAK,CAACyE,mBAAmB,KAAK,QAAQ,EAC7C;IACA,MAAMpI,KAAK,CAAC,0CAA0C,CAAC;EACzD;EAEA,OAAO2D,KAAK,CAACyE,mBAAmB;AAClC;AAEA,OAAO,SAASzD,qBAAqBA,CACnClH,GAAmB,EACe;EAClC;EACA,IAAIA,GAAG,CAAC4K,QAAQ,EAAEC,YAAY,EAAEC,EAAE,EAAE;IAClC,OAAO,CACL;MAAE3K,IAAI,EAAE,SAAS;MAAE4K,IAAI,EAAE;IAAQ,CAAC,EAClC;MAAE5K,IAAI,EAAE,SAAS;MAAE4K,IAAI,EAAE;IAAK,CAAC,CAChC;EACH;EACA,OAAO,EAAE;AACX","ignoreList":[]}
@@ -1,6 +1,7 @@
1
1
  import { type PaymentState } from '../../../../server/plugins/engine/components/PaymentField.types.js';
2
2
  import { type Field } from '../../../../server/plugins/engine/components/helpers/components.js';
3
3
  import { type BackLink, type ComponentViewModel } from '../../../../server/plugins/engine/components/types.js';
4
+ import { type Translator } from '../../../../server/plugins/engine/i18n/types.js';
4
5
  import { type Detail, type DetailItemField } from '../../../../server/plugins/engine/models/types.js';
5
6
  import { type PageControllerClass } from '../../../../server/plugins/engine/pageControllers/helpers/pages.js';
6
7
  import { type CheckAnswers, type FormContext, type FormContextRequest, type FormState, type FormSubmissionError } from '../../../../server/plugins/engine/types.js';
@@ -25,9 +26,11 @@ export declare class SummaryViewModel {
25
26
  allowSaveAndExit: boolean;
26
27
  paymentState?: PaymentState;
27
28
  paymentDetails?: CheckAnswers;
29
+ t: (key: string, opts?: Record<string, unknown>) => string;
30
+ private readonly _translator;
28
31
  paymentRequired?: boolean;
29
32
  paymentPreAuthorized?: boolean;
30
- constructor(request: FormContextRequest, page: PageControllerClass, context: FormContext);
33
+ constructor(request: FormContextRequest, page: PageControllerClass, context: FormContext, translator: Translator);
31
34
  private summaryDetails;
32
35
  }
33
36
  /**
@@ -37,4 +40,4 @@ export declare class SummaryViewModel {
37
40
  export declare function ItemField(page: PageControllerClass, state: FormState, field: Field, options: {
38
41
  path: string;
39
42
  errors?: FormSubmissionError[];
40
- }): DetailItemField;
43
+ }, translator: Translator): DetailItemField;
@@ -26,9 +26,11 @@ export class SummaryViewModel {
26
26
  allowSaveAndExit = false;
27
27
  paymentState;
28
28
  paymentDetails;
29
+ t;
30
+ _translator;
29
31
  paymentRequired;
30
32
  paymentPreAuthorized;
31
- constructor(request, page, context) {
33
+ constructor(request, page, context, translator) {
32
34
  const {
33
35
  model
34
36
  } = page;
@@ -40,10 +42,15 @@ export class SummaryViewModel {
40
42
  const {
41
43
  isForceAccess
42
44
  } = context;
45
+ const {
46
+ t
47
+ } = translator;
48
+ this.t = t;
49
+ this._translator = translator;
43
50
  this.page = page;
44
51
  this.pageTitle = page.title;
45
52
  if (def.schema === SchemaVersion.V2 && !page.title) {
46
- this.pageTitle = 'Check your answers before sending your form';
53
+ this.pageTitle = t('pages.summary.title');
47
54
  }
48
55
  this.serviceUrl = `/${basePath}`;
49
56
  this.name = def.name;
@@ -56,7 +63,7 @@ export class SummaryViewModel {
56
63
 
57
64
  // Format errors
58
65
  this.errors = result.error?.details.map(getError);
59
- this.details = this.summaryDetails(request, sections);
66
+ this.details = this.summaryDetails(request, sections, translator);
60
67
 
61
68
  // Format check answers
62
69
  this.checkAnswers = this.details.map(detail => {
@@ -70,7 +77,7 @@ export class SummaryViewModel {
70
77
  if (!isForceAccess) {
71
78
  items.push({
72
79
  href: item.href,
73
- text: 'Change',
80
+ text: t('pages.summary.change'),
74
81
  classes: 'govuk-link--no-visited-state',
75
82
  visuallyHiddenText: item.label
76
83
  });
@@ -81,7 +88,7 @@ export class SummaryViewModel {
81
88
  },
82
89
  value: {
83
90
  classes: 'app-prose-scope',
84
- html: item.value || 'Not provided'
91
+ html: item.value || t('pages.summary.notProvided')
85
92
  },
86
93
  actions: {
87
94
  items
@@ -98,7 +105,7 @@ export class SummaryViewModel {
98
105
  };
99
106
  });
100
107
  }
101
- summaryDetails(request, sections) {
108
+ summaryDetails(request, sections, translator) {
102
109
  const {
103
110
  context,
104
111
  errors
@@ -120,7 +127,7 @@ export class SummaryViewModel {
120
127
  items.push(ItemRepeat(page, state, {
121
128
  path: page.getSummaryPath(request),
122
129
  errors
123
- }));
130
+ }, translator));
124
131
  } else {
125
132
  for (const field of collection.fields) {
126
133
  // PaymentField is rendered in its own section, skip it here
@@ -130,14 +137,15 @@ export class SummaryViewModel {
130
137
  items.push(ItemField(page, state, field, {
131
138
  path,
132
139
  errors
133
- }));
140
+ }, translator));
134
141
  }
135
142
  }
136
143
  });
137
144
  if (items.length) {
145
+ const sectionTitle = section ? translator.tSection(section, 'title') || section.title : undefined;
138
146
  details.push({
139
147
  name: section?.name,
140
- title: section?.title,
148
+ title: sectionTitle,
141
149
  items
142
150
  });
143
151
  }
@@ -150,7 +158,7 @@ export class SummaryViewModel {
150
158
  * Creates a repeater detail item
151
159
  * @see {@link DetailItemField}
152
160
  */
153
- function ItemRepeat(page, state, options) {
161
+ function ItemRepeat(page, state, options, translator) {
154
162
  const {
155
163
  collection,
156
164
  repeat
@@ -160,19 +168,22 @@ function ItemRepeat(page, state, options) {
160
168
  title
161
169
  } = repeat.options;
162
170
  const values = page.getListFromState(state);
163
- const unit = values.length === 1 ? 'answer' : 'answers';
171
+ const count = values.length;
172
+ const value = count === 0 ? '' : translator.t('pages.repeater.pageTitle', {
173
+ count
174
+ });
164
175
  return {
165
176
  name,
166
177
  label: title,
167
178
  title,
168
- value: values.length ? `You have added ${values.length} ${unit}` : '',
179
+ value,
169
180
  href: getPageHref(page, options.path, {
170
181
  returnUrl: getPageHref(page, page.getSummaryPath())
171
182
  }),
172
183
  state,
173
184
  page,
174
185
  // Repeater field detail items
175
- subItems: values.map(repeatState => collection.fields.map(field => ItemField(page, repeatState, field, options)))
186
+ subItems: values.map(repeatState => collection.fields.map(field => ItemField(page, repeatState, field, options, translator)))
176
187
  };
177
188
  }
178
189
 
@@ -180,13 +191,28 @@ function ItemRepeat(page, state, options) {
180
191
  * Creates a form field detail item
181
192
  * @see {@link DetailItemField}
182
193
  */
183
- export function ItemField(page, state, field, options) {
194
+ export function ItemField(page, state, field, options, translator) {
195
+ // FormComponent doesn't expose shortDescription/title as raw def properties,
196
+ // so build a lookup object with English values to let tComponent's GUID lookup fire.
197
+ const fieldDef = {
198
+ id: field.id,
199
+ type: field.type,
200
+ shortDescription: field.label,
201
+ title: field.title
202
+ };
203
+ const rawLabel = translator.tComponent(fieldDef, 'shortDescription');
204
+ const translatedLabel = rawLabel !== '' ? rawLabel : field.label;
205
+ const rawTitle = translator.tComponent(fieldDef, 'title');
206
+ const translatedTitle = rawTitle !== '' ? rawTitle : field.title;
207
+ const optional = field.options.required === false ? ` ${translator.t('common.optional')}` : '';
184
208
  return {
185
209
  name: field.name,
186
- label: field.title,
187
- title: field.options.required === false ? `${field.summaryLabel} (optional)` : field.summaryLabel,
188
- error: field.getFirstError(options.errors),
189
- value: getAnswer(field, state),
210
+ label: translatedTitle,
211
+ title: `${translatedLabel}${optional}`,
212
+ error: field.getFirstError(translator, options.errors),
213
+ value: getAnswer(field, state, translator, {
214
+ format: 'summary'
215
+ }),
190
216
  href: getPageHref(page, options.path, {
191
217
  returnUrl: getPageHref(page, page.getSummaryPath())
192
218
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","paymentRequired","paymentPreAuthorized","constructor","request","model","basePath","def","sections","isForceAccess","title","schema","V2","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","required","summaryLabel","getFirstError"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import { SchemaVersion, type Section } from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} 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/pages.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 components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n paymentRequired?: boolean\n paymentPreAuthorized?: 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 if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = 'Check your answers before sending your form'\n }\n\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 provided'\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 ;[...sections, undefined].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 // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\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 ? 'answer' : 'answers'\n\n return {\n name,\n label: title,\n title,\n value: values.length ? `You have 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 */\nexport function 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:\n field.options.required === false\n ? `${field.summaryLabel} (optional)`\n : field.summaryLabel,\n error: field.getFirstError(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":[]}
1
+ {"version":3,"file":"SummaryViewModel.js","names":["SchemaVersion","PaymentField","getAnswer","evaluateTemplate","getError","getPageHref","RepeatPageController","validationOptions","opts","SummaryViewModel","page","pageTitle","declaration","details","checkAnswers","context","name","backLink","feedbackLink","phaseTag","errors","serviceUrl","hasMissingNotificationEmail","components","allowSaveAndExit","paymentState","paymentDetails","t","_translator","paymentRequired","paymentPreAuthorized","constructor","request","translator","model","basePath","def","sections","isForceAccess","title","schema","V2","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","sectionTitle","tSection","options","repeat","values","getListFromState","count","returnUrl","subItems","repeatState","fieldDef","id","type","shortDescription","rawLabel","tComponent","translatedLabel","rawTitle","translatedTitle","optional","required","getFirstError","format"],"sources":["../../../../../src/server/plugins/engine/models/SummaryViewModel.ts"],"sourcesContent":["import {\n SchemaVersion,\n type ComponentDef,\n type Section\n} from '@defra/forms-model'\n\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport {\n getAnswer,\n type Field\n} from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type BackLink,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport {\n evaluateTemplate,\n getError,\n getPageHref\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.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/pages.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 components?: ComponentViewModel[]\n allowSaveAndExit = false\n paymentState?: PaymentState\n paymentDetails?: CheckAnswers\n t: (key: string, opts?: Record<string, unknown>) => string\n private readonly _translator!: Translator\n paymentRequired?: boolean\n paymentPreAuthorized?: boolean\n\n constructor(\n request: FormContextRequest,\n page: PageControllerClass,\n context: FormContext,\n translator: Translator\n ) {\n const { model } = page\n const { basePath, def, sections } = model\n const { isForceAccess } = context\n\n const { t } = translator\n this.t = t\n this._translator = translator\n\n this.page = page\n this.pageTitle = page.title\n if (def.schema === SchemaVersion.V2 && !page.title) {\n this.pageTitle = t('pages.summary.title')\n }\n\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, translator)\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: t('pages.summary.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 || t('pages.summary.notProvided')\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(\n request: FormContextRequest,\n sections: Section[],\n translator: Translator\n ) {\n const { context, errors } = this\n const { relevantPages, state } = context\n\n const details: Detail[] = []\n\n ;[...sections, undefined].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(\n page,\n state,\n {\n path: page.getSummaryPath(request),\n errors\n },\n translator\n )\n )\n } else {\n for (const field of collection.fields) {\n // PaymentField is rendered in its own section, skip it here\n if (field instanceof PaymentField) {\n continue\n }\n items.push(\n ItemField(page, state, field, { path, errors }, translator)\n )\n }\n }\n })\n\n if (items.length) {\n const sectionTitle = section\n ? translator.tSection(section, 'title') || section.title\n : undefined\n details.push({\n name: section?.name,\n title: sectionTitle,\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 translator: Translator\n): DetailItemRepeat {\n const { collection, repeat } = page\n const { name, title } = repeat.options\n\n const values = page.getListFromState(state)\n const count = values.length\n const value =\n count === 0 ? '' : translator.t('pages.repeater.pageTitle', { count })\n\n return {\n name,\n label: title,\n title,\n value,\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, translator)\n )\n )\n }\n}\n\n/**\n * Creates a form field detail item\n * @see {@link DetailItemField}\n */\nexport function ItemField(\n page: PageControllerClass,\n state: FormState,\n field: Field,\n options: {\n path: string\n errors?: FormSubmissionError[]\n },\n translator: Translator\n): DetailItemField {\n // FormComponent doesn't expose shortDescription/title as raw def properties,\n // so build a lookup object with English values to let tComponent's GUID lookup fire.\n const fieldDef = {\n id: field.id,\n type: field.type,\n shortDescription: field.label,\n title: field.title\n } as unknown as ComponentDef\n const rawLabel = translator.tComponent(fieldDef, 'shortDescription')\n const translatedLabel = rawLabel !== '' ? rawLabel : field.label\n const rawTitle = translator.tComponent(fieldDef, 'title')\n const translatedTitle = rawTitle !== '' ? rawTitle : field.title\n const optional =\n field.options.required === false\n ? ` ${translator.t('common.optional')}`\n : ''\n return {\n name: field.name,\n label: translatedTitle,\n title: `${translatedLabel}${optional}`,\n error: field.getFirstError(translator, options.errors),\n value: getAnswer(field, state, translator, { format: 'summary' }),\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":[]}
@@ -20,7 +20,8 @@ const pluginRegistrationOptionsSchema = Joi.object({
20
20
  baseUrl: Joi.string().uri().required(),
21
21
  saveAndExit: Joi.function().optional(),
22
22
  ordnanceSurveyApiKey: Joi.string().optional(),
23
- ordnanceSurveyApiSecret: Joi.string().optional()
23
+ ordnanceSurveyApiSecret: Joi.string().optional(),
24
+ getLanguage: Joi.function().optional()
24
25
  });
25
26
 
26
27
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","names":["getErrorMessage","Joi","logger","CacheService","pluginRegistrationOptionsSchema","object","model","optional","services","controllers","pattern","string","any","cache","alternatives","try","instance","globals","filters","pluginPath","nunjucks","baseLayoutPath","required","paths","array","items","viewContext","function","preparePageEventRequestOptions","onRequest","baseUrl","uri","saveAndExit","ordnanceSurveyApiKey","ordnanceSurveyApiSecret","validatePluginOptions","options","result","validate","abortEarly","error","Error","value"],"sources":["../../../../src/server/plugins/engine/options.js"],"sourcesContent":["import { getErrorMessage } from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { CacheService } from '~/src/server/services/index.js'\n\nconst pluginRegistrationOptionsSchema = Joi.object({\n model: Joi.object().optional(),\n services: Joi.object().optional(),\n controllers: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n cache: Joi.alternatives().try(\n Joi.object().instance(CacheService),\n Joi.string()\n ),\n globals: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n filters: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n pluginPath: Joi.string().optional(),\n nunjucks: Joi.object({\n baseLayoutPath: Joi.string().required(),\n paths: Joi.array().items(Joi.string()).required()\n }).required(),\n viewContext: Joi.function().required(),\n preparePageEventRequestOptions: Joi.function().optional(),\n onRequest: Joi.function().optional(),\n baseUrl: Joi.string().uri().required(),\n saveAndExit: Joi.function().optional(),\n ordnanceSurveyApiKey: Joi.string().optional(),\n ordnanceSurveyApiSecret: Joi.string().optional()\n})\n\n/**\n * Validates the plugin options against the schema and returns the validated value.\n * @param {PluginOptions} options\n * @returns {PluginOptions}\n */\nexport function validatePluginOptions(options) {\n const result = pluginRegistrationOptionsSchema.validate(options, {\n abortEarly: false\n })\n\n if (result.error) {\n logger.error(\n result.error,\n `Missing required properties in plugin options: ${getErrorMessage(result.error)}`\n )\n throw new Error('Invalid plugin options', result.error)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return result.value\n}\n\n/**\n * @import { PluginOptions } from '~/src/server/plugins/engine/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"options.js","names":["getErrorMessage","Joi","logger","CacheService","pluginRegistrationOptionsSchema","object","model","optional","services","controllers","pattern","string","any","cache","alternatives","try","instance","globals","filters","pluginPath","nunjucks","baseLayoutPath","required","paths","array","items","viewContext","function","preparePageEventRequestOptions","onRequest","baseUrl","uri","saveAndExit","ordnanceSurveyApiKey","ordnanceSurveyApiSecret","getLanguage","validatePluginOptions","options","result","validate","abortEarly","error","Error","value"],"sources":["../../../../src/server/plugins/engine/options.js"],"sourcesContent":["import { getErrorMessage } from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { CacheService } from '~/src/server/services/index.js'\n\nconst pluginRegistrationOptionsSchema = Joi.object({\n model: Joi.object().optional(),\n services: Joi.object().optional(),\n controllers: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n cache: Joi.alternatives().try(\n Joi.object().instance(CacheService),\n Joi.string()\n ),\n globals: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n filters: Joi.object().pattern(Joi.string(), Joi.any()).optional(),\n pluginPath: Joi.string().optional(),\n nunjucks: Joi.object({\n baseLayoutPath: Joi.string().required(),\n paths: Joi.array().items(Joi.string()).required()\n }).required(),\n viewContext: Joi.function().required(),\n preparePageEventRequestOptions: Joi.function().optional(),\n onRequest: Joi.function().optional(),\n baseUrl: Joi.string().uri().required(),\n saveAndExit: Joi.function().optional(),\n ordnanceSurveyApiKey: Joi.string().optional(),\n ordnanceSurveyApiSecret: Joi.string().optional(),\n getLanguage: Joi.function().optional()\n})\n\n/**\n * Validates the plugin options against the schema and returns the validated value.\n * @param {PluginOptions} options\n * @returns {PluginOptions}\n */\nexport function validatePluginOptions(options) {\n const result = pluginRegistrationOptionsSchema.validate(options, {\n abortEarly: false\n })\n\n if (result.error) {\n logger.error(\n result.error,\n `Missing required properties in plugin options: ${getErrorMessage(result.error)}`\n )\n throw new Error('Invalid plugin options', result.error)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return result.value\n}\n\n/**\n * @import { PluginOptions } from '~/src/server/plugins/engine/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
@@ -22,6 +22,10 @@ export function format(context, items, model, submitResponse, formStatus, formMe
22
22
  if (versionMetadata) {
23
23
  meta.versionMetadata = versionMetadata;
24
24
  }
25
+ const definitionLanguage = model.def.metadata?.language;
26
+ if (typeof definitionLanguage === 'string') {
27
+ meta.language = definitionLanguage;
28
+ }
25
29
  const main = Object.fromEntries(Object.entries(v2Main).map(([key, value]) => {
26
30
  if (value === undefined) {
27
31
  return [key, null];
@@ -1 +1 @@
1
- {"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","Object","fromEntries","entries","map","key","value","undefined","data","result","files","payload","JSON","stringify","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport {\n getFormVersion,\n type checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { categoriseData } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const csvFiles = extractCsvFiles(submitResponse)\n\n const { main: v2Main, ...v2Data } = categoriseData(items)\n\n const versionMetadata = getFormVersion(model.def)\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.state,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? ''\n }\n\n if (versionMetadata) {\n meta.versionMetadata = versionMetadata\n }\n\n const main = Object.fromEntries(\n Object.entries(v2Main).map(([key, value]) => {\n if (value === undefined) {\n return [key, null]\n }\n\n return [key, value]\n })\n )\n\n const data: FormAdapterSubmissionMessageData = {\n main,\n ...v2Data\n }\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAKA,SACEA,cAAc;AAKhB,SAASC,cAAc;AACvB,SAASC,kCAAkC;AAS3C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,QAAQ,GAAGC,eAAe,CAACJ,cAAc,CAAC;EAEhD,MAAM;IAAEK,IAAI,EAAEC,MAAM;IAAE,GAAGC;EAAO,CAAC,GAAGb,cAAc,CAACI,KAAK,CAAC;EAEzD,MAAMU,eAAe,GAAGf,cAAc,CAACM,KAAK,CAACU,GAAG,CAAC;EAEjD,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEhB,kCAAkC,CAACiB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAElB,OAAO,CAACkB,eAAe;IACxCC,QAAQ,EAAEjB,KAAK,CAACkB,IAAI;IACpBC,MAAM,EAAEhB,YAAY,EAAEiB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAElB,YAAY,EAAEmB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAErB,UAAU,CAACsB,KAAK;IACxBC,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BC,iBAAiB,EAAEvB,YAAY,EAAEuB,iBAAiB,IAAI;EACxD,CAAC;EAED,IAAIjB,eAAe,EAAE;IACnBE,IAAI,CAACF,eAAe,GAAGA,eAAe;EACxC;EAEA,MAAMH,IAAI,GAAGqB,MAAM,CAACC,WAAW,CAC7BD,MAAM,CAACE,OAAO,CAACtB,MAAM,CAAC,CAACuB,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC3C,IAAIA,KAAK,KAAKC,SAAS,EAAE;MACvB,OAAO,CAACF,GAAG,EAAE,IAAI,CAAC;IACpB;IAEA,OAAO,CAACA,GAAG,EAAEC,KAAK,CAAC;EACrB,CAAC,CACH,CAAC;EAED,MAAME,IAAsC,GAAG;IAC7C5B,IAAI;IACJ,GAAGE;EACL,CAAC;EAED,MAAM2B,MAA0C,GAAG;IACjDC,KAAK,EAAEhC;EACT,CAAC;EAED,MAAMiC,OAA4C,GAAG;IACnD1B,IAAI;IACJuB,IAAI;IACJC;EACF,CAAC;EAED,OAAOG,IAAI,CAACC,SAAS,CAACF,OAAO,CAAC;AAChC;AAEA,SAAShC,eAAeA,CACtBJ,cAAqC,EACQ;EAC7C,MAAMkC,MAAM,GACVlC,cAAc,CAACkC,MAAqD;EAEtE,OAAO;IACL7B,IAAI,EAAE6B,MAAM,CAACC,KAAK,EAAE9B,IAAI,IAAI,EAAE;IAC9BkC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","definitionLanguage","metadata","language","Object","fromEntries","entries","map","key","value","undefined","data","result","files","payload","JSON","stringify","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport {\n getFormVersion,\n type checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { categoriseData } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const csvFiles = extractCsvFiles(submitResponse)\n\n const { main: v2Main, ...v2Data } = categoriseData(items)\n\n const versionMetadata = getFormVersion(model.def)\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.state,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? ''\n }\n\n if (versionMetadata) {\n meta.versionMetadata = versionMetadata\n }\n\n const definitionLanguage = model.def.metadata?.language\n if (typeof definitionLanguage === 'string') {\n meta.language = definitionLanguage\n }\n\n const main = Object.fromEntries(\n Object.entries(v2Main).map(([key, value]) => {\n if (value === undefined) {\n return [key, null]\n }\n\n return [key, value]\n })\n )\n\n const data: FormAdapterSubmissionMessageData = {\n main,\n ...v2Data\n }\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAKA,SACEA,cAAc;AAKhB,SAASC,cAAc;AACvB,SAASC,kCAAkC;AAS3C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,QAAQ,GAAGC,eAAe,CAACJ,cAAc,CAAC;EAEhD,MAAM;IAAEK,IAAI,EAAEC,MAAM;IAAE,GAAGC;EAAO,CAAC,GAAGb,cAAc,CAACI,KAAK,CAAC;EAEzD,MAAMU,eAAe,GAAGf,cAAc,CAACM,KAAK,CAACU,GAAG,CAAC;EAEjD,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEhB,kCAAkC,CAACiB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAElB,OAAO,CAACkB,eAAe;IACxCC,QAAQ,EAAEjB,KAAK,CAACkB,IAAI;IACpBC,MAAM,EAAEhB,YAAY,EAAEiB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAElB,YAAY,EAAEmB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAErB,UAAU,CAACsB,KAAK;IACxBC,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BC,iBAAiB,EAAEvB,YAAY,EAAEuB,iBAAiB,IAAI;EACxD,CAAC;EAED,IAAIjB,eAAe,EAAE;IACnBE,IAAI,CAACF,eAAe,GAAGA,eAAe;EACxC;EAEA,MAAMkB,kBAAkB,GAAG3B,KAAK,CAACU,GAAG,CAACkB,QAAQ,EAAEC,QAAQ;EACvD,IAAI,OAAOF,kBAAkB,KAAK,QAAQ,EAAE;IAC1ChB,IAAI,CAACkB,QAAQ,GAAGF,kBAAkB;EACpC;EAEA,MAAMrB,IAAI,GAAGwB,MAAM,CAACC,WAAW,CAC7BD,MAAM,CAACE,OAAO,CAACzB,MAAM,CAAC,CAAC0B,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC3C,IAAIA,KAAK,KAAKC,SAAS,EAAE;MACvB,OAAO,CAACF,GAAG,EAAE,IAAI,CAAC;IACpB;IAEA,OAAO,CAACA,GAAG,EAAEC,KAAK,CAAC;EACrB,CAAC,CACH,CAAC;EAED,MAAME,IAAsC,GAAG;IAC7C/B,IAAI;IACJ,GAAGE;EACL,CAAC;EAED,MAAM8B,MAA0C,GAAG;IACjDC,KAAK,EAAEnC;EACT,CAAC;EAED,MAAMoC,OAA4C,GAAG;IACnD7B,IAAI;IACJ0B,IAAI;IACJC;EACF,CAAC;EAED,OAAOG,IAAI,CAACC,SAAS,CAACF,OAAO,CAAC;AAChC;AAEA,SAASnC,eAAeA,CACtBJ,cAAqC,EACQ;EAC7C,MAAMqC,MAAM,GACVrC,cAAc,CAACqC,MAAqD;EAEtE,OAAO;IACLhC,IAAI,EAAEgC,MAAM,CAACC,KAAK,EAAEjC,IAAI,IAAI,EAAE;IAC9BqC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
@@ -6,6 +6,7 @@ import { PaymentField } from "../../components/index.js";
6
6
  import { formatCurrency, formatPaymentDate } from "../../../payment/helper.js";
7
7
  const designerUrl = config.get('designerUrl');
8
8
  export function format(_context, items, model, submitResponse, formStatus, _formMetadata) {
9
+ const translator = model.createTranslator();
9
10
  const {
10
11
  files
11
12
  } = submitResponse.result;
@@ -36,7 +37,7 @@ export function format(_context, items, model, submitResponse, formStatus, _form
36
37
  const fileId = files.repeaters[item.name];
37
38
  lines.push(`[${filename}](${designerUrl}/file-download/${fileId})\n`);
38
39
  } else {
39
- lines.push(getAnswer(item.field, item.state, {
40
+ lines.push(getAnswer(item.field, item.state, translator, {
40
41
  format: 'email'
41
42
  }));
42
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"v1.js","names":["addDays","format","dateFormat","config","getAnswer","escapeMarkdown","PaymentField","formatCurrency","formatPaymentDate","designerUrl","get","_context","items","model","submitResponse","formStatus","_formMetadata","files","result","formName","name","now","Date","formattedNow","fileExpiryDate","formattedExpiryDate","lines","push","isPreview","state","regularItems","filter","item","isPaymentItem","paymentItems","forEach","label","filename","fileId","repeaters","field","main","appendPaymentSection","join","length","paymentItem","paymentField","paymentState","getPaymentStateFromState","formattedAmount","amount","dateOfPayment","preAuth","createdAt","description"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/human/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { addDays, format as dateFormat } from 'date-fns'\n\nimport { config } from '~/src/config/index.js'\nimport { getAnswer } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { PaymentField } 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} from '~/src/server/plugins/engine/models/types.js'\nimport { type FormContext } from '~/src/server/plugins/engine/types.js'\nimport {\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n _context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n _formMetadata?: FormMetadata\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(`${formName} form received at ${escapeMarkdown(formattedNow)}.\\n`)\n lines.push('---\\n')\n\n const regularItems = items.filter((item) => !isPaymentItem(item))\n const paymentItems = items.filter((item) => isPaymentItem(item))\n\n regularItems.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 appendPaymentSection(paymentItems, lines)\n\n return lines.join('\\n')\n}\n\n/**\n * Check if an item is a PaymentField\n */\nfunction isPaymentItem(item: DetailItem): boolean {\n if ('subItems' in item) {\n return false\n }\n return item.field instanceof PaymentField\n}\n\n/**\n * Appends the payment details section to the email lines if payment exists\n */\nfunction appendPaymentSection(paymentItems: DetailItem[], lines: string[]) {\n if (paymentItems.length === 0) {\n return\n }\n\n const paymentItem = paymentItems[0] as DetailItemField\n const paymentField = paymentItem.field as PaymentField\n const paymentState = paymentField.getPaymentStateFromState(paymentItem.state)\n\n if (!paymentState) {\n return\n }\n\n const formattedAmount = formatCurrency(paymentState.amount)\n const dateOfPayment = paymentState.preAuth?.createdAt\n ? formatPaymentDate(paymentState.preAuth.createdAt)\n : ''\n\n lines.push(\n '---\\n',\n `# Your payment of ${formattedAmount} was successful\\n`,\n '## Payment for\\n',\n `${escapeMarkdown(paymentState.description)}\\n`,\n '---\\n',\n '## Total amount\\n',\n `${formattedAmount}\\n`,\n '---\\n',\n '## Date of payment\\n',\n `${escapeMarkdown(dateOfPayment)}\\n`,\n '---\\n'\n )\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"v1.js","names":["addDays","format","dateFormat","config","getAnswer","escapeMarkdown","PaymentField","formatCurrency","formatPaymentDate","designerUrl","get","_context","items","model","submitResponse","formStatus","_formMetadata","translator","createTranslator","files","result","formName","name","now","Date","formattedNow","fileExpiryDate","formattedExpiryDate","lines","push","isPreview","state","regularItems","filter","item","isPaymentItem","paymentItems","forEach","label","filename","fileId","repeaters","field","main","appendPaymentSection","join","length","paymentItem","paymentField","paymentState","getPaymentStateFromState","formattedAmount","amount","dateOfPayment","preAuth","createdAt","description"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/human/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { addDays, format as dateFormat } from 'date-fns'\n\nimport { config } from '~/src/config/index.js'\nimport { getAnswer } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { PaymentField } 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} from '~/src/server/plugins/engine/models/types.js'\nimport { type FormContext } from '~/src/server/plugins/engine/types.js'\nimport {\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n _context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n _formMetadata?: FormMetadata\n) {\n const translator = model.createTranslator()\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(`${formName} form received at ${escapeMarkdown(formattedNow)}.\\n`)\n lines.push('---\\n')\n\n const regularItems = items.filter((item) => !isPaymentItem(item))\n const paymentItems = items.filter((item) => isPaymentItem(item))\n\n regularItems.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, translator, { format: 'email' })\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 appendPaymentSection(paymentItems, lines)\n\n return lines.join('\\n')\n}\n\n/**\n * Check if an item is a PaymentField\n */\nfunction isPaymentItem(item: DetailItem): boolean {\n if ('subItems' in item) {\n return false\n }\n return item.field instanceof PaymentField\n}\n\n/**\n * Appends the payment details section to the email lines if payment exists\n */\nfunction appendPaymentSection(paymentItems: DetailItem[], lines: string[]) {\n if (paymentItems.length === 0) {\n return\n }\n\n const paymentItem = paymentItems[0] as DetailItemField\n const paymentField = paymentItem.field as PaymentField\n const paymentState = paymentField.getPaymentStateFromState(paymentItem.state)\n\n if (!paymentState) {\n return\n }\n\n const formattedAmount = formatCurrency(paymentState.amount)\n const dateOfPayment = paymentState.preAuth?.createdAt\n ? formatPaymentDate(paymentState.preAuth.createdAt)\n : ''\n\n lines.push(\n '---\\n',\n `# Your payment of ${formattedAmount} was successful\\n`,\n '## Payment for\\n',\n `${escapeMarkdown(paymentState.description)}\\n`,\n '---\\n',\n '## Total amount\\n',\n `${formattedAmount}\\n`,\n '---\\n',\n '## Date of payment\\n',\n `${escapeMarkdown(dateOfPayment)}\\n`,\n '---\\n'\n )\n}\n"],"mappings":"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","ignoreList":[]}