@defra/forms-engine-plugin 4.0.34 → 4.0.36

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.
@@ -83,7 +83,8 @@ export class DeclarationField extends FormComponent {
83
83
  classes: 'govuk-fieldset__legend--m'
84
84
  }
85
85
  };
86
- const isChecked = payload[this.name] === 'true' || payload[this.name] === true;
86
+ const payloadValue = payload[this.name];
87
+ const isChecked = payloadValue === 'true' || payloadValue === true || Array.isArray(payloadValue) && payloadValue.some(x => x === 'true');
87
88
  return {
88
89
  ...viewModel,
89
90
  hint: hint ? {
@@ -1 +1 @@
1
- {"version":3,"file":"DeclarationField.js","names":["ComponentType","hasFormComponents","isFormType","joi","FormComponent","isFormValue","messageTemplate","DeclarationField","DEFAULT_DECLARATION_LABEL","headerStartLevel","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","formComponents","page","pageDef","components","numOfQuestionsOnPage","filter","q","type","length","hasGuidance","some","comp","idx","Markdown","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","every","v","getContextValueFromFormValue","getFormValue","undefined","getDisplayStringFromFormValue","getViewModel","errors","defaultDeclarationConfirmationLabel","hint","viewModel","fieldset","legend","text","classes","isChecked","checked","Array","isArray","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import {\n ComponentType,\n hasFormComponents,\n isFormType,\n type DeclarationFieldComponent,\n type Item\n} from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n private readonly DEFAULT_DECLARATION_LABEL = 'I understand and agree'\n\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n headerStartLevel: number\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n this.declarationConfirmationLabel =\n options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL\n const formComponents = hasFormComponents(props.page?.pageDef)\n ? props.page.pageDef.components\n : []\n const numOfQuestionsOnPage = formComponents.filter((q) =>\n isFormType(q.type)\n ).length\n const hasGuidance = formComponents.some(\n (comp, idx) => comp.type === ComponentType.Markdown && idx === 0\n )\n this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n return value === 'true' ? this.declarationConfirmationLabel : 'Not provided'\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const defaultDeclarationConfirmationLabel =\n 'I confirm that I understand and accept this declaration'\n const {\n hint,\n content,\n declarationConfirmationLabel = defaultDeclarationConfirmationLabel\n } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const isChecked =\n payload[this.name] === 'true' || payload[this.name] === true\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ],\n headerStartLevel: this.headerStartLevel\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"DeclarationField.js","names":["ComponentType","hasFormComponents","isFormType","joi","FormComponent","isFormValue","messageTemplate","DeclarationField","DEFAULT_DECLARATION_LABEL","headerStartLevel","constructor","def","props","options","content","checkboxSchema","string","valid","required","formSchema","array","items","strip","label","single","messages","declarationRequired","stateSchema","boolean","cast","declarationConfirmationLabel","formComponents","page","pageDef","components","numOfQuestionsOnPage","filter","q","type","length","hasGuidance","some","comp","idx","Markdown","getFormValueFromState","state","name","getFormDataFromState","getStateFromValidForm","payload","payloadValue","value","isValue","every","v","getContextValueFromFormValue","getFormValue","undefined","getDisplayStringFromFormValue","getViewModel","errors","defaultDeclarationConfirmationLabel","hint","viewModel","fieldset","legend","text","classes","isChecked","Array","isArray","x","checked","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isBool"],"sources":["../../../../../src/server/plugins/engine/components/DeclarationField.ts"],"sourcesContent":["import {\n ComponentType,\n hasFormComponents,\n isFormType,\n type DeclarationFieldComponent,\n type Item\n} from '@defra/forms-model'\nimport joi, {\n type ArraySchema,\n type BooleanSchema,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\n\nexport class DeclarationField extends FormComponent {\n private readonly DEFAULT_DECLARATION_LABEL = 'I understand and agree'\n\n declare options: DeclarationFieldComponent['options']\n\n declare declarationConfirmationLabel: string\n\n declare formSchema: ArraySchema<StringSchema[]>\n declare stateSchema: BooleanSchema\n declare content: string\n headerStartLevel: number\n\n constructor(\n def: DeclarationFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options, content } = def\n\n let checkboxSchema = joi.string().valid('true')\n\n if (options.required !== false) {\n checkboxSchema = checkboxSchema.required()\n }\n\n const formSchema = joi\n .array()\n .items(checkboxSchema, joi.string().valid('unchecked').strip())\n .label(this.label)\n .single()\n .messages({\n 'any.required': messageTemplate.declarationRequired as string,\n 'any.unknown': messageTemplate.declarationRequired as string,\n 'array.includesRequiredUnknowns':\n messageTemplate.declarationRequired as string\n }) as ArraySchema<StringSchema[]>\n\n this.formSchema = formSchema\n this.stateSchema = joi.boolean().cast('string').label(this.label).required()\n\n this.options = options\n this.content = content\n this.declarationConfirmationLabel =\n options.declarationConfirmationLabel ?? this.DEFAULT_DECLARATION_LABEL\n const formComponents = hasFormComponents(props.page?.pageDef)\n ? props.page.pageDef.components\n : []\n const numOfQuestionsOnPage = formComponents.filter((q) =>\n isFormType(q.type)\n ).length\n const hasGuidance = formComponents.some(\n (comp, idx) => comp.type === ComponentType.Markdown && idx === 0\n )\n this.headerStartLevel = numOfQuestionsOnPage < 2 && !hasGuidance ? 2 : 3\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return state[name] === true ? 'true' : 'false'\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { name } = this\n return { [name]: state[name] === true ? 'true' : 'false' }\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { name } = this\n const payloadValue = payload[name]\n const value =\n this.isValue(payloadValue) &&\n payloadValue.length > 0 &&\n payloadValue.every((v) => {\n return v === 'true'\n })\n\n return { [name]: value }\n }\n\n getContextValueFromFormValue(value: FormValue | FormPayload): boolean {\n return value === 'true'\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n return value === 'true' ? this.declarationConfirmationLabel : 'Not provided'\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const defaultDeclarationConfirmationLabel =\n 'I confirm that I understand and accept this declaration'\n const {\n hint,\n content,\n declarationConfirmationLabel = defaultDeclarationConfirmationLabel\n } = this\n\n const viewModel = super.getViewModel(payload, errors)\n let { fieldset, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n classes: 'govuk-fieldset__legend--m'\n }\n }\n\n const payloadValue = payload[this.name]\n const isChecked =\n payloadValue === 'true' ||\n payloadValue === true ||\n (Array.isArray(payloadValue) && payloadValue.some((x) => x === 'true'))\n\n return {\n ...viewModel,\n hint: hint ? { text: hint } : undefined,\n fieldset,\n content,\n items: [\n {\n text: declarationConfirmationLabel,\n value: 'true',\n checked: isChecked\n }\n ],\n headerStartLevel: this.headerStartLevel\n }\n }\n\n isValue(value?: FormStateValue | FormState): value is Item['value'][] {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isFormValue)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return DeclarationField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.declarationRequired }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isBool(value?: FormStateValue | FormState): value is boolean {\n return isFormValue(value) && typeof value === 'boolean'\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -6,5 +6,7 @@ export { context } from '~/src/server/plugins/nunjucks/context.js';
6
6
  export { getFirstJourneyPage, getFormContext, getFormModel, resolveFormModel } from '~/src/server/plugins/engine/beta/form-context.js';
7
7
  export declare const VIEW_PATH = "src/server/plugins/engine/views";
8
8
  export declare const PLUGIN_PATH = "node_modules/@defra/forms-engine-plugin";
9
+ export declare const STATE_NOT_YET_VALIDATED = "__stateNotYetValidated";
10
+ export declare const CURRENT_PAGE_PATH_KEY = "__currentPagePath";
9
11
  export declare const prepareNunjucksEnvironment: (env: Environment, pluginOptions: PluginOptions) => void;
10
12
  export default plugin;
@@ -14,6 +14,8 @@ const globals = {
14
14
  };
15
15
  export const VIEW_PATH = 'src/server/plugins/engine/views';
16
16
  export const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin';
17
+ export const STATE_NOT_YET_VALIDATED = '__stateNotYetValidated';
18
+ export const CURRENT_PAGE_PATH_KEY = '__currentPagePath';
17
19
  export const prepareNunjucksEnvironment = function (env, pluginOptions) {
18
20
  for (const [name, nunjucksFilter] of Object.entries(filters)) {
19
21
  env.addFilter(name, nunjucksFilter);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","filters","getPageHref","context","getFirstJourneyPage","getFormContext","getFormModel","resolveFormModel","globals","VIEW_PATH","PLUGIN_PATH","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","startingHeaderLevel","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\nexport {\n getFirstJourneyPage,\n getFormContext,\n getFormModel,\n resolveFormModel\n} from '~/src/server/plugins/engine/beta/form-context.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>\n markdownToHtml(text, {\n baseUrl: pluginOptions.baseUrl,\n startingHeaderLevel\n })\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY;AAEd,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAChB,SACEC,mBAAmB,EACnBC,cAAc,EACdC,YAAY,EACZC,gBAAgB;AAGlB,MAAMC,OAAO,GAAG;EACdX,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC;AACF,CAAC;AAED,OAAO,MAAMS,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAAChB,OAAO,CAAC,EAAE;IAC5DW,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAE,CAACC,IAAY,EAAEC,mBAA4B,KACnE1B,cAAc,CAACyB,IAAI,EAAE;IACnBE,OAAO,EAAER,aAAa,CAACQ,OAAO;IAC9BD;EACF,CAAC,CACH,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEQ,cAAc,CAAC,IAAIN,MAAM,CAACC,OAAO,CAACT,OAAO,CAAC,EAAE;IAC5DI,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEQ,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIT,aAAa,CAACZ,OAAO,EAAE;IACzB,KAAK,MAAM,CAACa,IAAI,EAAEU,MAAM,CAAC,IAAIR,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACZ,OAAO,CAAC,EAAE;MAClEW,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEU,MAAM,CAAC;MAC3B7B,MAAM,CAAC8B,cAAc,CAACX,IAAI,EAAEU,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIX,aAAa,CAACL,OAAO,EAAE;IACzBQ,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACL,OAAO,CAAC,CAACkB,OAAO,CAAC,CAAC,CAACZ,IAAI,EAAEa,EAAE,CAAC,KAAK;MAC5Df,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEa,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAe/B,MAAM","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","filters","getPageHref","context","getFirstJourneyPage","getFormContext","getFormModel","resolveFormModel","globals","VIEW_PATH","PLUGIN_PATH","STATE_NOT_YET_VALIDATED","CURRENT_PAGE_PATH_KEY","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","startingHeaderLevel","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\nexport {\n getFirstJourneyPage,\n getFormContext,\n getFormModel,\n resolveFormModel\n} from '~/src/server/plugins/engine/beta/form-context.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const STATE_NOT_YET_VALIDATED = '__stateNotYetValidated'\nexport const CURRENT_PAGE_PATH_KEY = '__currentPagePath'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>\n markdownToHtml(text, {\n baseUrl: pluginOptions.baseUrl,\n startingHeaderLevel\n })\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY;AAEd,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAChB,SACEC,mBAAmB,EACnBC,cAAc,EACdC,YAAY,EACZC,gBAAgB;AAGlB,MAAMC,OAAO,GAAG;EACdX,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC;AACF,CAAC;AAED,OAAO,MAAMS,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,uBAAuB,GAAG,wBAAwB;AAC/D,OAAO,MAAMC,qBAAqB,GAAG,mBAAmB;AAExD,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAAClB,OAAO,CAAC,EAAE;IAC5Da,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAE,CAACC,IAAY,EAAEC,mBAA4B,KACnE5B,cAAc,CAAC2B,IAAI,EAAE;IACnBE,OAAO,EAAER,aAAa,CAACQ,OAAO;IAC9BD;EACF,CAAC,CACH,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEQ,cAAc,CAAC,IAAIN,MAAM,CAACC,OAAO,CAACX,OAAO,CAAC,EAAE;IAC5DM,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEQ,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIT,aAAa,CAACd,OAAO,EAAE;IACzB,KAAK,MAAM,CAACe,IAAI,EAAEU,MAAM,CAAC,IAAIR,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACd,OAAO,CAAC,EAAE;MAClEa,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEU,MAAM,CAAC;MAC3B/B,MAAM,CAACgC,cAAc,CAACX,IAAI,EAAEU,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIX,aAAa,CAACP,OAAO,EAAE;IACzBU,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACP,OAAO,CAAC,CAACoB,OAAO,CAAC,CAAC,CAACZ,IAAI,EAAEa,EAAE,CAAC,KAAK;MAC5Df,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEa,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAejC,MAAM","ignoreList":[]}
@@ -8,6 +8,7 @@ import { hasListFormField } from "../components/helpers/components.js";
8
8
  import { todayAsDateOnly } from "../date-helper.js";
9
9
  import { findPage, getError, getPage, setPageTitles } from "../helpers.js";
10
10
  import { createPage } from "../pageControllers/helpers/pages.js";
11
+ import { copyNotYetValidatedState } from "../pageControllers/helpers/state.js";
11
12
  import { validationOptions as opts } from "../pageControllers/validationOptions.js";
12
13
  import * as defaultServices from "../services/index.js";
13
14
  import { FormAction } from "../../../routes/types.js";
@@ -264,6 +265,9 @@ export class FormModel {
264
265
 
265
266
  // Add paths for navigation
266
267
  this.assignPaths(context);
268
+
269
+ // Handle restoration of payload from say a 'save-and-exit' request
270
+ copyNotYetValidatedState(request, context);
267
271
  return context;
268
272
  }
269
273
  initialiseContext(context) {
@@ -1 +1 @@
1
- {"version":3,"file":"FormModel.js","names":["ComponentType","ConditionsModel","ControllerPath","ControllerType","SchemaVersion","convertConditionWrapperFromV2","formDefinitionSchema","formDefinitionV2Schema","generateConditionAlias","hasComponents","hasRepeater","isConditionWrapperV2","yesNoListId","yesNoListName","add","format","Parser","joi","createLogger","hasListFormField","todayAsDateOnly","findPage","getError","getPage","setPageTitles","createPage","validationOptions","opts","defaultServices","FormAction","merge","logger","FormModel","engine","schemaVersion","def","lists","sections","name","formId","values","basePath","versionNumber","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","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","submittedVersionNumber","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","action","getFormParams","Validate","startsWith","External","update","CheckboxesField","formState","getStateFromValidForm","previousPages","relevantPage","model","stripUnknown","errorsState","details","$$__referenceNumber","Error"],"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 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 { createLogger } 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\nconst logger = createLogger()\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 versionNumber?: number\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 versionNumber?: number\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.versionNumber = options.versionNumber\n this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey\n this.conditions = {}\n this.services = services\n this.controllers = controllers\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 submittedVersionNumber: this.versionNumber\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/**\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":"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","ignoreList":[]}
1
+ {"version":3,"file":"FormModel.js","names":["ComponentType","ConditionsModel","ControllerPath","ControllerType","SchemaVersion","convertConditionWrapperFromV2","formDefinitionSchema","formDefinitionV2Schema","generateConditionAlias","hasComponents","hasRepeater","isConditionWrapperV2","yesNoListId","yesNoListName","add","format","Parser","joi","createLogger","hasListFormField","todayAsDateOnly","findPage","getError","getPage","setPageTitles","createPage","copyNotYetValidatedState","validationOptions","opts","defaultServices","FormAction","merge","logger","FormModel","engine","schemaVersion","def","lists","sections","name","formId","values","basePath","versionNumber","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","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","submittedVersionNumber","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","action","getFormParams","Validate","startsWith","External","update","CheckboxesField","formState","getStateFromValidForm","previousPages","relevantPage","model","stripUnknown","errorsState","details","$$__referenceNumber","Error"],"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 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 { createLogger } 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 { copyNotYetValidatedState } from '~/src/server/plugins/engine/pageControllers/helpers/state.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\nconst logger = createLogger()\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 versionNumber?: number\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 versionNumber?: number\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.versionNumber = options.versionNumber\n this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey\n this.conditions = {}\n this.services = services\n this.controllers = controllers\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 submittedVersionNumber: this.versionNumber\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 // Handle restoration of payload from say a 'save-and-exit' request\n copyNotYetValidatedState(request, 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/**\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":"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","ignoreList":[]}
@@ -5,7 +5,7 @@ import { ComponentCollection } from "../components/ComponentCollection.js";
5
5
  import { optionalText } from "../components/constants.js";
6
6
  import { getCacheService, getErrors, getSaveAndExitHelpers, normalisePath, proceed } from "../helpers.js";
7
7
  import { PageController } from "./PageController.js";
8
- import { prefillStateFromQueryParameters } from "./helpers/state.js";
8
+ import { clearNotYetValidatedState, prefillStateFromQueryParameters } from "./helpers/state.js";
9
9
  import { getComponentsByType } from "../validationHelpers.js";
10
10
  import { FormAction } from "../../../routes/types.js";
11
11
  import { actionSchema, crumbSchema, paramsSchema } from "../../../schemas/index.js";
@@ -268,7 +268,9 @@ export class QuestionPageController extends PageController {
268
268
  return state;
269
269
  }
270
270
  const cacheService = getCacheService(request.server);
271
- return cacheService.setState(request, state);
271
+
272
+ // Clear any 'not yet validated' state before saving to cache
273
+ return cacheService.setState(request, clearNotYetValidatedState(state));
272
274
  }
273
275
  async mergeState(request, state, update) {
274
276
  const {
@@ -1 +1 @@
1
- {"version":3,"file":"QuestionPageController.js","names":["ComponentType","ControllerType","Engine","hasComponents","hasNext","hasRepeater","Boom","COMPONENT_STATE_ERROR","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","ComponentCollection","optionalText","getCacheService","getErrors","getSaveAndExitHelpers","normalisePath","proceed","PageController","prefillStateFromQueryParameters","getComponentsByType","FormAction","actionSchema","crumbSchema","paramsSchema","merge","QuestionPageController","collection","errorSummaryTitle","allowSaveAndExit","constructor","model","pageDef","components","page","formSchema","keys","crumb","action","next","def","filter","path","linkPath","pages","some","pagePath","allowContinue","engine","V2","controller","Terminal","length","getItemId","request","itemId","getFormParams","params","getViewModel","context","viewModel","query","payload","errors","pageTitle","showTitle","formComponents","isFormComponent","fieldset","label","isPageHeading","labelOrLegend","legend","size","classes","isOptional","fields","at","options","required","text","backLink","getBackLink","shouldShowSaveAndExit","server","getRelevantPath","paths","startPath","getStartPath","relevantPath","getNextPath","evaluationState","summaryPath","getSummaryPath","statusPath","getStatusPath","defaultPath","undefined","pageIndex","indexOf","nextPage","slice","find","condition","conditionResult","fn","nextLink","link","conditions","getFormDataFromState","state","result","validate","abortEarly","stripUnknown","value","getStateFromValidForm","details","getState","cacheService","setState","mergeState","update","updated","filterConditionalComponents","filtered","component","content","type","Details","map","evaluatedComponent","Array","isArray","item","items","makeGetRouteHandler","h","viewName","redirect","url","origin","pathname","getViewErrors","flashedError","yar","flash","flashedErrors","concat","hasMissingNotificationEmail","view","isForceAccess","formsService","services","getFormMetadata","includes","notificationEmail","slug","returnUrl","href","backPath","endsWith","getHref","makePostRouteHandler","startsWith","External","dispatchExternal","SaveAndExit","handleSaveAndExit","externalComponents","externalActionsWithArgs","split","externalActionArgs","arg","args","Object","fromEntries","componentName","componentDefMap","get","componentType","internal","selectedComponent","stashedPayload","clear","dispatcher","sourceUrl","toString","actionArgs","nextPath","nextUrl","saveAndExit","getRouteOptions","ext","onPostHandler","method","_request","continue","postRouteOptions","parse","maxBytes","Number","MAX_SAFE_INTEGER","failAction"],"sources":["../../../../../src/server/plugins/engine/pageControllers/QuestionPageController.ts"],"sourcesContent":["import {\n ComponentType,\n ControllerType,\n Engine,\n hasComponents,\n hasNext,\n hasRepeater,\n type Link,\n type Page\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n COMPONENT_STATE_ERROR,\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport { type BackLink } from '~/src/server/plugins/engine/components/types.js'\nimport {\n getCacheService,\n getErrors,\n getSaveAndExitHelpers,\n normalisePath,\n proceed\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { prefillStateFromQueryParameters } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormPayloadParams,\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { getComponentsByType } from '~/src/server/plugins/engine/validationHelpers.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n paramsSchema\n} from '~/src/server/schemas/index.js'\nimport { merge } from '~/src/server/services/cacheService.js'\n\nexport class QuestionPageController extends PageController {\n collection: ComponentCollection\n errorSummaryTitle = 'There is a problem'\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponents(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n\n this.collection.formSchema = this.collection.formSchema.keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n }\n\n get next(): Link[] {\n const { def, pageDef } = this\n\n if (!hasNext(pageDef)) {\n return []\n }\n\n // Remove stale links\n return pageDef.next.filter(({ path }) => {\n const linkPath = normalisePath(path)\n\n return def.pages.some((page) => {\n const pagePath = normalisePath(page.path)\n return pagePath === linkPath\n })\n })\n }\n\n get allowContinue(): boolean {\n if (this.model.engine === Engine.V2) {\n return this.pageDef.controller !== ControllerType.Terminal\n }\n\n return this.next.length > 0\n }\n\n getItemId(request?: FormContextRequest) {\n const { itemId } = this.getFormParams(request)\n return itemId ?? request?.params.itemId\n }\n\n /**\n * Used for mapping form payloads and errors to govuk-frontend's template api, so a page can be rendered\n * @param request - the hapi request\n * @param context - the form context\n */\n getViewModel(\n request: FormContextRequest,\n context: FormContext\n ): FormPageViewModel {\n const { collection, viewModel } = this\n const { query } = request\n const { payload, errors } = context\n\n let { pageTitle, showTitle } = viewModel\n\n const components = collection.getViewModel(payload, errors, query)\n const formComponents = components.filter(\n ({ isFormComponent }) => isFormComponent\n )\n\n // Single form component? Hide title and customise label or legend instead\n if (formComponents.length === 1) {\n const { model } = formComponents[0]\n const { fieldset, label } = model\n\n // Set as page heading when not following other content\n const isPageHeading = formComponents[0] === components[0]\n\n // Check for legend or label\n const labelOrLegend = fieldset?.legend ?? label\n\n // Use legend or label as page heading\n if (labelOrLegend) {\n const size = isPageHeading ? 'l' : 'm'\n\n labelOrLegend.classes =\n labelOrLegend === label\n ? `govuk-label--${size}`\n : `govuk-fieldset__legend--${size}`\n\n if (isPageHeading) {\n labelOrLegend.isPageHeading = isPageHeading\n\n // Check for optional in label\n const isOptional =\n this.collection.fields.at(0)?.options.required === false\n\n if (pageTitle) {\n labelOrLegend.text = isOptional\n ? `${pageTitle}${optionalText}`\n : pageTitle\n }\n\n pageTitle = pageTitle || labelOrLegend.text\n }\n }\n\n showTitle = !isPageHeading\n } else if (formComponents.length > 1) {\n // When there is more than one form component,\n // adjust the label/legends to give equal prominence\n for (const { model } of formComponents) {\n if (model.fieldset?.legend) {\n model.fieldset.legend.classes = 'govuk-fieldset__legend--m'\n }\n if (model.label) {\n model.label.classes = 'govuk-label--m'\n }\n }\n }\n\n return {\n ...viewModel,\n backLink: this.getBackLink(request, context),\n context,\n showTitle,\n components,\n errors,\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getRelevantPath(request: AnyFormRequest, context: FormContext) {\n const { paths } = context\n\n const startPath = this.getStartPath()\n const relevantPath = paths.at(-1) ?? startPath\n\n return !paths.length\n ? startPath // First possible path\n : relevantPath // Last possible path\n }\n\n /**\n * Apply conditions to evaluation state to determine next page path\n */\n getNextPath(context: FormContext) {\n const { model, next, path } = this\n const { evaluationState } = context\n\n const summaryPath = this.getSummaryPath()\n const statusPath = this.getStatusPath()\n\n // Walk from summary page (no next links) to status page\n let defaultPath = path === summaryPath ? statusPath : undefined\n\n if (model.engine === Engine.V2) {\n if (this.pageDef.controller !== ControllerType.Terminal) {\n const { pages } = this.model\n const pageIndex = pages.indexOf(this)\n\n // The \"next\" page is the first found after the current which is\n // either unconditional or has a condition that evaluates to \"true\"\n const nextPage = pages.slice(pageIndex + 1).find((page) => {\n const { condition } = page\n\n if (condition) {\n const conditionResult = condition.fn(evaluationState)\n\n if (!conditionResult) {\n return false\n }\n }\n\n return true\n })\n\n return nextPage?.path ?? defaultPath\n } else {\n return defaultPath\n }\n }\n\n const nextLink = next.find((link) => {\n const { condition } = link\n\n if (condition) {\n return model.conditions[condition]?.fn(evaluationState) ?? false\n }\n\n defaultPath = link.path\n return false\n })\n\n return nextLink?.path ?? defaultPath\n }\n\n /**\n * Gets the form payload (from state) for this page only\n */\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ): FormPayload {\n const { collection } = this\n\n // Form params from request\n const params = this.getFormParams(request)\n\n // Form payload from state\n const payload = collection.getFormDataFromState(state)\n\n return {\n ...params,\n ...payload\n }\n }\n\n /**\n * Gets form params (from payload) for this page only\n */\n getFormParams(request?: FormContextRequest): FormPayloadParams {\n const { payload } = request ?? {}\n\n const result = paramsSchema.validate(payload, {\n abortEarly: false,\n stripUnknown: true\n })\n\n return result.value as FormPayloadParams\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ): FormState {\n return this.collection.getStateFromValidForm(payload)\n }\n\n getErrors(details?: ValidationErrorItem[]) {\n return getErrors(details)\n }\n\n async getState(request: AnyFormRequest) {\n const { query } = request\n\n // Skip get for preview URL direct access\n if ('force' in query) {\n return {}\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.getState(request)\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const { query } = request\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return state\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, state)\n }\n\n async mergeState(\n request: AnyFormRequest,\n state: FormSubmissionState,\n update: object\n ) {\n const { query } = request\n\n // Merge state before set\n const updated = merge(state, update)\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return updated\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, updated)\n }\n\n filterConditionalComponents(\n viewModel: FormPageViewModel,\n model: FormModel,\n evaluationState: Partial<Record<string, FormStateValue>>\n ) {\n // Filter our components based on their conditions using our evaluated state\n let filtered = viewModel.components.filter((component) => {\n if (\n (!!component.model.content ||\n component.type === ComponentType.Details) &&\n component.model.condition\n ) {\n const condition = model.conditions[component.model.condition]\n return condition?.fn(evaluationState)\n }\n return true\n })\n\n /**\n * For conditional reveal components (which we no longer support until GDS resolves the related accessibility issues {@link https://github.com/alphagov/govuk-frontend/issues/1991}\n */\n filtered = filtered.map((component) => {\n const evaluatedComponent = component\n const content = evaluatedComponent.model.content\n if (Array.isArray(content)) {\n evaluatedComponent.model.content = content.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n // apply condition to items for radios, checkboxes etc\n const items = evaluatedComponent.model.items\n\n if (Array.isArray(items)) {\n evaluatedComponent.model.items = items.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n\n return evaluatedComponent\n })\n\n return filtered\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, model, viewName } = this\n const { evaluationState } = context\n\n // Copy any URL params into the form state (if not already done so)\n if (await prefillStateFromQueryParameters(request, this)) {\n // Forward to same page without query string\n return h.redirect(`${request.url.origin}${request.url.pathname}`)\n }\n\n const viewModel = this.getViewModel(request, context)\n viewModel.errors = collection.getViewErrors(viewModel.errors)\n\n const flashedError = request.yar.flash(COMPONENT_STATE_ERROR)\n const flashedErrors = !Array.isArray(flashedError) ? [flashedError] : []\n\n viewModel.errors = (viewModel.errors ?? []).concat(flashedErrors)\n\n /**\n * Content components can be hidden based on a condition. If the condition evaluates to true, it is safe to be kept, otherwise discard it\n */\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, viewModel)\n }\n }\n\n async hasMissingNotificationEmail(\n request: FormRequest,\n context: FormContext\n ) {\n const { path } = this\n const { params } = request\n const { isForceAccess } = context\n\n const startPath = this.getStartPath()\n const summaryPath = this.getSummaryPath()\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Warn the user if the form has no notification email set only on start page and summary page\n if ([startPath, summaryPath].includes(path) && !isForceAccess) {\n const { notificationEmail } = await getFormMetadata(params.slug)\n return !notificationEmail\n }\n\n return false\n }\n\n /**\n * Get the back link for a given progress.\n */\n protected getBackLink(\n request: FormContextRequest,\n context: FormContext\n ): BackLink | undefined {\n const { pageDef } = this\n const { path, query } = request\n const { returnUrl } = query\n const { paths } = context\n\n const itemId = this.getItemId(request)\n\n // Check answers back link\n if (returnUrl) {\n return {\n text:\n hasRepeater(pageDef) && itemId\n ? 'Go back to add another'\n : 'Go back to check answers',\n href: returnUrl\n }\n }\n\n // Item delete pages etc\n const backPath =\n itemId && !path.endsWith(itemId)\n ? paths.at(-1) // Back to main page\n : paths.at(-2) // Back to previous page\n\n // No back link\n if (!backPath) {\n return\n }\n\n // Default back link\n return {\n text: 'Back',\n href: this.getHref(backPath)\n }\n }\n\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, viewName, model } = this\n const { isForceAccess, state, evaluationState } = context\n const action = request.payload.action\n\n if (action?.startsWith(FormAction.External)) {\n return this.dispatchExternal(request, h, context)\n }\n\n /**\n * If there are any errors, render the page with the parsed errors\n * @todo Refactor to match POST REDIRECT GET pattern\n */\n if (context.errors || isForceAccess) {\n const viewModel = this.getViewModel(request, context)\n viewModel.errors = collection.getViewErrors(viewModel.errors)\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n return h.view(viewName, viewModel)\n }\n\n // Save state\n await this.setState(request, state)\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n // Proceed to the next page\n return this.proceed(request, h, this.getNextPath(context))\n }\n }\n\n private dispatchExternal(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n ) {\n const { externalComponents } = getComponentsByType()\n const action = request.payload.action ?? ''\n\n // Find the external action and arguments\n // `external-{componentName}--{argname1}:{argvalue1}--{argname2}:{argvalue2}`\n // E.g. external-abcdef--amount:10--step:manual\n const externalActionsWithArgs = action\n .slice(`${FormAction.External}-`.length)\n .split('--')\n\n const externalActionArgs = externalActionsWithArgs\n .slice(1)\n .map((arg) => arg.split(':'))\n\n const args = Object.fromEntries(externalActionArgs) as Record<\n string,\n string\n >\n\n const componentName = externalActionsWithArgs[0]\n const component = this.model.componentDefMap.get(componentName)\n const componentType = component?.type\n\n if (!componentType) {\n throw Boom.internal(\n `External component of type ${componentType} not found`\n )\n }\n\n const selectedComponent = externalComponents.get(componentType)\n\n if (!selectedComponent) {\n throw Boom.internal(`External component ${componentName} not found`)\n }\n\n // Stash payload without crumb and action\n const stashedPayload = {\n ...context.payload,\n crumb: undefined,\n action: undefined\n }\n request.yar.flash(EXTERNAL_STATE_PAYLOAD, stashedPayload, true)\n\n // Clear any previous state appendage\n request.yar.clear(EXTERNAL_STATE_APPENDAGE)\n\n return selectedComponent.dispatcher(request, h, {\n component,\n controller: this,\n sourceUrl: request.url.toString(),\n actionArgs: args\n })\n }\n\n proceed(\n request: FormContextRequest,\n h: FormResponseToolkit,\n nextPath?: string\n ) {\n const nextUrl = nextPath\n ? this.getHref(nextPath) // Redirect to next page\n : this.href // Redirect to current page (refresh)\n\n return proceed(request, h, nextUrl)\n }\n\n /**\n * Handle save-and-exit action\n */\n handleSaveAndExit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const saveAndExit = getSaveAndExitHelpers(request.server)\n\n if (!saveAndExit) {\n throw Boom.internal('Server misconfigured for save and exit')\n }\n\n return saveAndExit(request, h, context)\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get getRouteOptions(): RouteOptions<FormRequestRefs> {\n return {\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n payload: {\n parse: true,\n maxBytes: Number.MAX_SAFE_INTEGER,\n failAction: 'ignore'\n },\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"QuestionPageController.js","names":["ComponentType","ControllerType","Engine","hasComponents","hasNext","hasRepeater","Boom","COMPONENT_STATE_ERROR","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","ComponentCollection","optionalText","getCacheService","getErrors","getSaveAndExitHelpers","normalisePath","proceed","PageController","clearNotYetValidatedState","prefillStateFromQueryParameters","getComponentsByType","FormAction","actionSchema","crumbSchema","paramsSchema","merge","QuestionPageController","collection","errorSummaryTitle","allowSaveAndExit","constructor","model","pageDef","components","page","formSchema","keys","crumb","action","next","def","filter","path","linkPath","pages","some","pagePath","allowContinue","engine","V2","controller","Terminal","length","getItemId","request","itemId","getFormParams","params","getViewModel","context","viewModel","query","payload","errors","pageTitle","showTitle","formComponents","isFormComponent","fieldset","label","isPageHeading","labelOrLegend","legend","size","classes","isOptional","fields","at","options","required","text","backLink","getBackLink","shouldShowSaveAndExit","server","getRelevantPath","paths","startPath","getStartPath","relevantPath","getNextPath","evaluationState","summaryPath","getSummaryPath","statusPath","getStatusPath","defaultPath","undefined","pageIndex","indexOf","nextPage","slice","find","condition","conditionResult","fn","nextLink","link","conditions","getFormDataFromState","state","result","validate","abortEarly","stripUnknown","value","getStateFromValidForm","details","getState","cacheService","setState","mergeState","update","updated","filterConditionalComponents","filtered","component","content","type","Details","map","evaluatedComponent","Array","isArray","item","items","makeGetRouteHandler","h","viewName","redirect","url","origin","pathname","getViewErrors","flashedError","yar","flash","flashedErrors","concat","hasMissingNotificationEmail","view","isForceAccess","formsService","services","getFormMetadata","includes","notificationEmail","slug","returnUrl","href","backPath","endsWith","getHref","makePostRouteHandler","startsWith","External","dispatchExternal","SaveAndExit","handleSaveAndExit","externalComponents","externalActionsWithArgs","split","externalActionArgs","arg","args","Object","fromEntries","componentName","componentDefMap","get","componentType","internal","selectedComponent","stashedPayload","clear","dispatcher","sourceUrl","toString","actionArgs","nextPath","nextUrl","saveAndExit","getRouteOptions","ext","onPostHandler","method","_request","continue","postRouteOptions","parse","maxBytes","Number","MAX_SAFE_INTEGER","failAction"],"sources":["../../../../../src/server/plugins/engine/pageControllers/QuestionPageController.ts"],"sourcesContent":["import {\n ComponentType,\n ControllerType,\n Engine,\n hasComponents,\n hasNext,\n hasRepeater,\n type Link,\n type Page\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n COMPONENT_STATE_ERROR,\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport { type BackLink } from '~/src/server/plugins/engine/components/types.js'\nimport {\n getCacheService,\n getErrors,\n getSaveAndExitHelpers,\n normalisePath,\n proceed\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n clearNotYetValidatedState,\n prefillStateFromQueryParameters\n} from '~/src/server/plugins/engine/pageControllers/helpers/state.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormPayloadParams,\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { getComponentsByType } from '~/src/server/plugins/engine/validationHelpers.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n paramsSchema\n} from '~/src/server/schemas/index.js'\nimport { merge } from '~/src/server/services/cacheService.js'\n\nexport class QuestionPageController extends PageController {\n collection: ComponentCollection\n errorSummaryTitle = 'There is a problem'\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponents(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n\n this.collection.formSchema = this.collection.formSchema.keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n }\n\n get next(): Link[] {\n const { def, pageDef } = this\n\n if (!hasNext(pageDef)) {\n return []\n }\n\n // Remove stale links\n return pageDef.next.filter(({ path }) => {\n const linkPath = normalisePath(path)\n\n return def.pages.some((page) => {\n const pagePath = normalisePath(page.path)\n return pagePath === linkPath\n })\n })\n }\n\n get allowContinue(): boolean {\n if (this.model.engine === Engine.V2) {\n return this.pageDef.controller !== ControllerType.Terminal\n }\n\n return this.next.length > 0\n }\n\n getItemId(request?: FormContextRequest) {\n const { itemId } = this.getFormParams(request)\n return itemId ?? request?.params.itemId\n }\n\n /**\n * Used for mapping form payloads and errors to govuk-frontend's template api, so a page can be rendered\n * @param request - the hapi request\n * @param context - the form context\n */\n getViewModel(\n request: FormContextRequest,\n context: FormContext\n ): FormPageViewModel {\n const { collection, viewModel } = this\n const { query } = request\n const { payload, errors } = context\n\n let { pageTitle, showTitle } = viewModel\n\n const components = collection.getViewModel(payload, errors, query)\n const formComponents = components.filter(\n ({ isFormComponent }) => isFormComponent\n )\n\n // Single form component? Hide title and customise label or legend instead\n if (formComponents.length === 1) {\n const { model } = formComponents[0]\n const { fieldset, label } = model\n\n // Set as page heading when not following other content\n const isPageHeading = formComponents[0] === components[0]\n\n // Check for legend or label\n const labelOrLegend = fieldset?.legend ?? label\n\n // Use legend or label as page heading\n if (labelOrLegend) {\n const size = isPageHeading ? 'l' : 'm'\n\n labelOrLegend.classes =\n labelOrLegend === label\n ? `govuk-label--${size}`\n : `govuk-fieldset__legend--${size}`\n\n if (isPageHeading) {\n labelOrLegend.isPageHeading = isPageHeading\n\n // Check for optional in label\n const isOptional =\n this.collection.fields.at(0)?.options.required === false\n\n if (pageTitle) {\n labelOrLegend.text = isOptional\n ? `${pageTitle}${optionalText}`\n : pageTitle\n }\n\n pageTitle = pageTitle || labelOrLegend.text\n }\n }\n\n showTitle = !isPageHeading\n } else if (formComponents.length > 1) {\n // When there is more than one form component,\n // adjust the label/legends to give equal prominence\n for (const { model } of formComponents) {\n if (model.fieldset?.legend) {\n model.fieldset.legend.classes = 'govuk-fieldset__legend--m'\n }\n if (model.label) {\n model.label.classes = 'govuk-label--m'\n }\n }\n }\n\n return {\n ...viewModel,\n backLink: this.getBackLink(request, context),\n context,\n showTitle,\n components,\n errors,\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getRelevantPath(request: AnyFormRequest, context: FormContext) {\n const { paths } = context\n\n const startPath = this.getStartPath()\n const relevantPath = paths.at(-1) ?? startPath\n\n return !paths.length\n ? startPath // First possible path\n : relevantPath // Last possible path\n }\n\n /**\n * Apply conditions to evaluation state to determine next page path\n */\n getNextPath(context: FormContext) {\n const { model, next, path } = this\n const { evaluationState } = context\n\n const summaryPath = this.getSummaryPath()\n const statusPath = this.getStatusPath()\n\n // Walk from summary page (no next links) to status page\n let defaultPath = path === summaryPath ? statusPath : undefined\n\n if (model.engine === Engine.V2) {\n if (this.pageDef.controller !== ControllerType.Terminal) {\n const { pages } = this.model\n const pageIndex = pages.indexOf(this)\n\n // The \"next\" page is the first found after the current which is\n // either unconditional or has a condition that evaluates to \"true\"\n const nextPage = pages.slice(pageIndex + 1).find((page) => {\n const { condition } = page\n\n if (condition) {\n const conditionResult = condition.fn(evaluationState)\n\n if (!conditionResult) {\n return false\n }\n }\n\n return true\n })\n\n return nextPage?.path ?? defaultPath\n } else {\n return defaultPath\n }\n }\n\n const nextLink = next.find((link) => {\n const { condition } = link\n\n if (condition) {\n return model.conditions[condition]?.fn(evaluationState) ?? false\n }\n\n defaultPath = link.path\n return false\n })\n\n return nextLink?.path ?? defaultPath\n }\n\n /**\n * Gets the form payload (from state) for this page only\n */\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ): FormPayload {\n const { collection } = this\n\n // Form params from request\n const params = this.getFormParams(request)\n\n // Form payload from state\n const payload = collection.getFormDataFromState(state)\n\n return {\n ...params,\n ...payload\n }\n }\n\n /**\n * Gets form params (from payload) for this page only\n */\n getFormParams(request?: FormContextRequest): FormPayloadParams {\n const { payload } = request ?? {}\n\n const result = paramsSchema.validate(payload, {\n abortEarly: false,\n stripUnknown: true\n })\n\n return result.value as FormPayloadParams\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ): FormState {\n return this.collection.getStateFromValidForm(payload)\n }\n\n getErrors(details?: ValidationErrorItem[]) {\n return getErrors(details)\n }\n\n async getState(request: AnyFormRequest) {\n const { query } = request\n\n // Skip get for preview URL direct access\n if ('force' in query) {\n return {}\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.getState(request)\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const { query } = request\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return state\n }\n\n const cacheService = getCacheService(request.server)\n\n // Clear any 'not yet validated' state before saving to cache\n return cacheService.setState(request, clearNotYetValidatedState(state))\n }\n\n async mergeState(\n request: AnyFormRequest,\n state: FormSubmissionState,\n update: object\n ) {\n const { query } = request\n\n // Merge state before set\n const updated = merge(state, update)\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return updated\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, updated)\n }\n\n filterConditionalComponents(\n viewModel: FormPageViewModel,\n model: FormModel,\n evaluationState: Partial<Record<string, FormStateValue>>\n ) {\n // Filter our components based on their conditions using our evaluated state\n let filtered = viewModel.components.filter((component) => {\n if (\n (!!component.model.content ||\n component.type === ComponentType.Details) &&\n component.model.condition\n ) {\n const condition = model.conditions[component.model.condition]\n return condition?.fn(evaluationState)\n }\n return true\n })\n\n /**\n * For conditional reveal components (which we no longer support until GDS resolves the related accessibility issues {@link https://github.com/alphagov/govuk-frontend/issues/1991}\n */\n filtered = filtered.map((component) => {\n const evaluatedComponent = component\n const content = evaluatedComponent.model.content\n if (Array.isArray(content)) {\n evaluatedComponent.model.content = content.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n // apply condition to items for radios, checkboxes etc\n const items = evaluatedComponent.model.items\n\n if (Array.isArray(items)) {\n evaluatedComponent.model.items = items.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n\n return evaluatedComponent\n })\n\n return filtered\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, model, viewName } = this\n const { evaluationState } = context\n\n // Copy any URL params into the form state (if not already done so)\n if (await prefillStateFromQueryParameters(request, this)) {\n // Forward to same page without query string\n return h.redirect(`${request.url.origin}${request.url.pathname}`)\n }\n\n const viewModel = this.getViewModel(request, context)\n viewModel.errors = collection.getViewErrors(viewModel.errors)\n\n const flashedError = request.yar.flash(COMPONENT_STATE_ERROR)\n const flashedErrors = !Array.isArray(flashedError) ? [flashedError] : []\n\n viewModel.errors = (viewModel.errors ?? []).concat(flashedErrors)\n\n /**\n * Content components can be hidden based on a condition. If the condition evaluates to true, it is safe to be kept, otherwise discard it\n */\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, viewModel)\n }\n }\n\n async hasMissingNotificationEmail(\n request: FormRequest,\n context: FormContext\n ) {\n const { path } = this\n const { params } = request\n const { isForceAccess } = context\n\n const startPath = this.getStartPath()\n const summaryPath = this.getSummaryPath()\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Warn the user if the form has no notification email set only on start page and summary page\n if ([startPath, summaryPath].includes(path) && !isForceAccess) {\n const { notificationEmail } = await getFormMetadata(params.slug)\n return !notificationEmail\n }\n\n return false\n }\n\n /**\n * Get the back link for a given progress.\n */\n protected getBackLink(\n request: FormContextRequest,\n context: FormContext\n ): BackLink | undefined {\n const { pageDef } = this\n const { path, query } = request\n const { returnUrl } = query\n const { paths } = context\n\n const itemId = this.getItemId(request)\n\n // Check answers back link\n if (returnUrl) {\n return {\n text:\n hasRepeater(pageDef) && itemId\n ? 'Go back to add another'\n : 'Go back to check answers',\n href: returnUrl\n }\n }\n\n // Item delete pages etc\n const backPath =\n itemId && !path.endsWith(itemId)\n ? paths.at(-1) // Back to main page\n : paths.at(-2) // Back to previous page\n\n // No back link\n if (!backPath) {\n return\n }\n\n // Default back link\n return {\n text: 'Back',\n href: this.getHref(backPath)\n }\n }\n\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, viewName, model } = this\n const { isForceAccess, state, evaluationState } = context\n const action = request.payload.action\n\n if (action?.startsWith(FormAction.External)) {\n return this.dispatchExternal(request, h, context)\n }\n\n /**\n * If there are any errors, render the page with the parsed errors\n * @todo Refactor to match POST REDIRECT GET pattern\n */\n if (context.errors || isForceAccess) {\n const viewModel = this.getViewModel(request, context)\n viewModel.errors = collection.getViewErrors(viewModel.errors)\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n return h.view(viewName, viewModel)\n }\n\n // Save state\n await this.setState(request, state)\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n // Proceed to the next page\n return this.proceed(request, h, this.getNextPath(context))\n }\n }\n\n private dispatchExternal(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n ) {\n const { externalComponents } = getComponentsByType()\n const action = request.payload.action ?? ''\n\n // Find the external action and arguments\n // `external-{componentName}--{argname1}:{argvalue1}--{argname2}:{argvalue2}`\n // E.g. external-abcdef--amount:10--step:manual\n const externalActionsWithArgs = action\n .slice(`${FormAction.External}-`.length)\n .split('--')\n\n const externalActionArgs = externalActionsWithArgs\n .slice(1)\n .map((arg) => arg.split(':'))\n\n const args = Object.fromEntries(externalActionArgs) as Record<\n string,\n string\n >\n\n const componentName = externalActionsWithArgs[0]\n const component = this.model.componentDefMap.get(componentName)\n const componentType = component?.type\n\n if (!componentType) {\n throw Boom.internal(\n `External component of type ${componentType} not found`\n )\n }\n\n const selectedComponent = externalComponents.get(componentType)\n\n if (!selectedComponent) {\n throw Boom.internal(`External component ${componentName} not found`)\n }\n\n // Stash payload without crumb and action\n const stashedPayload = {\n ...context.payload,\n crumb: undefined,\n action: undefined\n }\n request.yar.flash(EXTERNAL_STATE_PAYLOAD, stashedPayload, true)\n\n // Clear any previous state appendage\n request.yar.clear(EXTERNAL_STATE_APPENDAGE)\n\n return selectedComponent.dispatcher(request, h, {\n component,\n controller: this,\n sourceUrl: request.url.toString(),\n actionArgs: args\n })\n }\n\n proceed(\n request: FormContextRequest,\n h: FormResponseToolkit,\n nextPath?: string\n ) {\n const nextUrl = nextPath\n ? this.getHref(nextPath) // Redirect to next page\n : this.href // Redirect to current page (refresh)\n\n return proceed(request, h, nextUrl)\n }\n\n /**\n * Handle save-and-exit action\n */\n handleSaveAndExit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const saveAndExit = getSaveAndExitHelpers(request.server)\n\n if (!saveAndExit) {\n throw Boom.internal('Server misconfigured for save and exit')\n }\n\n return saveAndExit(request, h, context)\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get getRouteOptions(): RouteOptions<FormRequestRefs> {\n return {\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n payload: {\n parse: true,\n maxBytes: Number.MAX_SAFE_INTEGER,\n failAction: 'ignore'\n },\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js';
2
- import { type AnyFormRequest } from '~/src/server/plugins/engine/types.js';
2
+ import { type AnyFormRequest, type FormContext, type FormContextRequest, type FormSubmissionState } from '~/src/server/plugins/engine/types.js';
3
3
  import { type FormQuery } from '~/src/server/routes/types.js';
4
4
  export declare function stripParam(query: FormQuery, paramToRemove: string): FormQuery | undefined;
5
5
  /**
@@ -9,3 +9,15 @@ export declare function stripParam(query: FormQuery, paramToRemove: string): For
9
9
  * @param model
10
10
  */
11
11
  export declare function prefillStateFromQueryParameters(request: AnyFormRequest, page: PageControllerClass): Promise<boolean>;
12
+ /**
13
+ * Copies any potentially invalid state into the payload, and removes those values from state
14
+ * NOTE - this method has a side-effect on 'context.state' and 'context.payload'
15
+ * @param request - the form request
16
+ * @param context - the form context
17
+ */
18
+ export declare function copyNotYetValidatedState(request: FormContextRequest, context: FormContext): void;
19
+ /**
20
+ * Remove any temporary 'not yet validated' state now that it's been validated
21
+ * @param state - the form state
22
+ */
23
+ export declare function clearNotYetValidatedState(state: FormSubmissionState): FormSubmissionState;
@@ -1,4 +1,5 @@
1
1
  import { getHiddenFields } from '@defra/forms-model';
2
+ import { CURRENT_PAGE_PATH_KEY, STATE_NOT_YET_VALIDATED } from "../../index.js";
2
3
  /**
3
4
  * A series of functions that can transform a pre-fill input parameter e.g lookup a form title based on form id
4
5
  */
@@ -63,4 +64,36 @@ export async function prefillStateFromQueryParameters(request, page) {
63
64
  await page.mergeState(request, formData, params);
64
65
  return true;
65
66
  }
67
+
68
+ /**
69
+ * Copies any potentially invalid state into the payload, and removes those values from state
70
+ * NOTE - this method has a side-effect on 'context.state' and 'context.payload'
71
+ * @param request - the form request
72
+ * @param context - the form context
73
+ */
74
+ export function copyNotYetValidatedState(request, context) {
75
+ const potentiallyInvalidState = context.state[STATE_NOT_YET_VALIDATED];
76
+ if (!potentiallyInvalidState) {
77
+ return;
78
+ }
79
+ const originalPath = potentiallyInvalidState[CURRENT_PAGE_PATH_KEY];
80
+ if (originalPath && originalPath === request.url.pathname) {
81
+ context.payload = {
82
+ ...context.payload,
83
+ ...potentiallyInvalidState,
84
+ [CURRENT_PAGE_PATH_KEY]: undefined
85
+ };
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Remove any temporary 'not yet validated' state now that it's been validated
91
+ * @param state - the form state
92
+ */
93
+ export function clearNotYetValidatedState(state) {
94
+ if (state[STATE_NOT_YET_VALIDATED]) {
95
+ state[STATE_NOT_YET_VALIDATED] = undefined;
96
+ }
97
+ return state;
98
+ }
66
99
  //# sourceMappingURL=state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","names":["getHiddenFields","paramLookupFunctions","formId","val","services","formTitle","meta","formsService","getFormMetadataById","title","key","value","stripParam","query","paramToRemove","params","Object","entries","keys","length","undefined","prefillStateFromQueryParameters","request","page","model","hiddenFieldNames","Set","def","map","field","name","size","has","lookupFunc","res","formData","getState","mergeState"],"sources":["../../../../../../src/server/plugins/engine/pageControllers/helpers/state.ts"],"sourcesContent":["import { getHiddenFields } from '@defra/forms-model'\n\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n type AnyFormRequest,\n type FormStateValue\n} from '~/src/server/plugins/engine/types.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\nimport { type Services } from '~/src/server/types.js'\n\n/**\n * A series of functions that can transform a pre-fill input parameter e.g lookup a form title based on form id\n */\nconst paramLookupFunctions = {\n formId: async (val: string, services: Services) => {\n let formTitle\n if (val) {\n const meta = await services.formsService.getFormMetadataById(val)\n formTitle = meta.title\n }\n return {\n key: 'formName',\n value: formTitle\n }\n }\n} as Partial<\n Record<\n string,\n (\n val: string,\n services: Services\n ) => Promise<{ key: string; value: string | undefined }>\n >\n>\n\nexport function stripParam(query: FormQuery, paramToRemove: string) {\n const params = {} as Record<string, FormStateValue | undefined>\n for (const [key, value = ''] of Object.entries(query)) {\n if (key !== paramToRemove) {\n params[key] = value\n }\n }\n return Object.keys(params).length ? (params as FormQuery) : undefined\n}\n\n/**\n * Any hidden parameters defined in the FormDefinition may be pre-filled by URL parameter values.\n * Other parameters are ignored for security reasons.\n * @param request\n * @param model\n */\nexport async function prefillStateFromQueryParameters(\n request: AnyFormRequest,\n page: PageControllerClass\n): Promise<boolean> {\n const { model } = page\n\n const hiddenFieldNames = new Set(\n getHiddenFields(model.def).map((field) => field.name)\n )\n\n if (!hiddenFieldNames.size) {\n return false\n }\n\n // Remove 'returnUrl' param\n const query = stripParam(request.query, 'returnUrl')\n\n if (!query) {\n return false\n }\n\n const params = {} as Record<string, FormStateValue | undefined>\n\n for (const [key, value = ''] of Object.entries(query)) {\n if (hiddenFieldNames.has(key)) {\n const lookupFunc = paramLookupFunctions[key]\n if (lookupFunc) {\n const res = await lookupFunc(value, model.services)\n // Store original value and result\n params[key] = value\n params[res.key] = res.value\n } else {\n params[key] = value\n }\n }\n }\n\n const formData = await page.getState(request)\n await page.mergeState(request, formData, params)\n\n return true\n}\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,oBAAoB;AAUpD;AACA;AACA;AACA,MAAMC,oBAAoB,GAAG;EAC3BC,MAAM,EAAE,MAAAA,CAAOC,GAAW,EAAEC,QAAkB,KAAK;IACjD,IAAIC,SAAS;IACb,IAAIF,GAAG,EAAE;MACP,MAAMG,IAAI,GAAG,MAAMF,QAAQ,CAACG,YAAY,CAACC,mBAAmB,CAACL,GAAG,CAAC;MACjEE,SAAS,GAAGC,IAAI,CAACG,KAAK;IACxB;IACA,OAAO;MACLC,GAAG,EAAE,UAAU;MACfC,KAAK,EAAEN;IACT,CAAC;EACH;AACF,CAQC;AAED,OAAO,SAASO,UAAUA,CAACC,KAAgB,EAAEC,aAAqB,EAAE;EAClE,MAAMC,MAAM,GAAG,CAAC,CAA+C;EAC/D,KAAK,MAAM,CAACL,GAAG,EAAEC,KAAK,GAAG,EAAE,CAAC,IAAIK,MAAM,CAACC,OAAO,CAACJ,KAAK,CAAC,EAAE;IACrD,IAAIH,GAAG,KAAKI,aAAa,EAAE;MACzBC,MAAM,CAACL,GAAG,CAAC,GAAGC,KAAK;IACrB;EACF;EACA,OAAOK,MAAM,CAACE,IAAI,CAACH,MAAM,CAAC,CAACI,MAAM,GAAIJ,MAAM,GAAiBK,SAAS;AACvE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,+BAA+BA,CACnDC,OAAuB,EACvBC,IAAyB,EACP;EAClB,MAAM;IAAEC;EAAM,CAAC,GAAGD,IAAI;EAEtB,MAAME,gBAAgB,GAAG,IAAIC,GAAG,CAC9B1B,eAAe,CAACwB,KAAK,CAACG,GAAG,CAAC,CAACC,GAAG,CAAEC,KAAK,IAAKA,KAAK,CAACC,IAAI,CACtD,CAAC;EAED,IAAI,CAACL,gBAAgB,CAACM,IAAI,EAAE;IAC1B,OAAO,KAAK;EACd;;EAEA;EACA,MAAMlB,KAAK,GAAGD,UAAU,CAACU,OAAO,CAACT,KAAK,EAAE,WAAW,CAAC;EAEpD,IAAI,CAACA,KAAK,EAAE;IACV,OAAO,KAAK;EACd;EAEA,MAAME,MAAM,GAAG,CAAC,CAA+C;EAE/D,KAAK,MAAM,CAACL,GAAG,EAAEC,KAAK,GAAG,EAAE,CAAC,IAAIK,MAAM,CAACC,OAAO,CAACJ,KAAK,CAAC,EAAE;IACrD,IAAIY,gBAAgB,CAACO,GAAG,CAACtB,GAAG,CAAC,EAAE;MAC7B,MAAMuB,UAAU,GAAGhC,oBAAoB,CAACS,GAAG,CAAC;MAC5C,IAAIuB,UAAU,EAAE;QACd,MAAMC,GAAG,GAAG,MAAMD,UAAU,CAACtB,KAAK,EAAEa,KAAK,CAACpB,QAAQ,CAAC;QACnD;QACAW,MAAM,CAACL,GAAG,CAAC,GAAGC,KAAK;QACnBI,MAAM,CAACmB,GAAG,CAACxB,GAAG,CAAC,GAAGwB,GAAG,CAACvB,KAAK;MAC7B,CAAC,MAAM;QACLI,MAAM,CAACL,GAAG,CAAC,GAAGC,KAAK;MACrB;IACF;EACF;EAEA,MAAMwB,QAAQ,GAAG,MAAMZ,IAAI,CAACa,QAAQ,CAACd,OAAO,CAAC;EAC7C,MAAMC,IAAI,CAACc,UAAU,CAACf,OAAO,EAAEa,QAAQ,EAAEpB,MAAM,CAAC;EAEhD,OAAO,IAAI;AACb","ignoreList":[]}
1
+ {"version":3,"file":"state.js","names":["getHiddenFields","CURRENT_PAGE_PATH_KEY","STATE_NOT_YET_VALIDATED","paramLookupFunctions","formId","val","services","formTitle","meta","formsService","getFormMetadataById","title","key","value","stripParam","query","paramToRemove","params","Object","entries","keys","length","undefined","prefillStateFromQueryParameters","request","page","model","hiddenFieldNames","Set","def","map","field","name","size","has","lookupFunc","res","formData","getState","mergeState","copyNotYetValidatedState","context","potentiallyInvalidState","state","originalPath","url","pathname","payload","clearNotYetValidatedState"],"sources":["../../../../../../src/server/plugins/engine/pageControllers/helpers/state.ts"],"sourcesContent":["import { getHiddenFields } from '@defra/forms-model'\n\nimport {\n CURRENT_PAGE_PATH_KEY,\n STATE_NOT_YET_VALIDATED\n} from '~/src/server/plugins/engine/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormContextRequest,\n type FormStateValue,\n type FormSubmissionState,\n type FormValue\n} from '~/src/server/plugins/engine/types.js'\nimport { type FormQuery } from '~/src/server/routes/types.js'\nimport { type Services } from '~/src/server/types.js'\n\n/**\n * A series of functions that can transform a pre-fill input parameter e.g lookup a form title based on form id\n */\nconst paramLookupFunctions = {\n formId: async (val: string, services: Services) => {\n let formTitle\n if (val) {\n const meta = await services.formsService.getFormMetadataById(val)\n formTitle = meta.title\n }\n return {\n key: 'formName',\n value: formTitle\n }\n }\n} as Partial<\n Record<\n string,\n (\n val: string,\n services: Services\n ) => Promise<{ key: string; value: string | undefined }>\n >\n>\n\nexport function stripParam(query: FormQuery, paramToRemove: string) {\n const params = {} as Record<string, FormStateValue | undefined>\n for (const [key, value = ''] of Object.entries(query)) {\n if (key !== paramToRemove) {\n params[key] = value\n }\n }\n return Object.keys(params).length ? (params as FormQuery) : undefined\n}\n\n/**\n * Any hidden parameters defined in the FormDefinition may be pre-filled by URL parameter values.\n * Other parameters are ignored for security reasons.\n * @param request\n * @param model\n */\nexport async function prefillStateFromQueryParameters(\n request: AnyFormRequest,\n page: PageControllerClass\n): Promise<boolean> {\n const { model } = page\n\n const hiddenFieldNames = new Set(\n getHiddenFields(model.def).map((field) => field.name)\n )\n\n if (!hiddenFieldNames.size) {\n return false\n }\n\n // Remove 'returnUrl' param\n const query = stripParam(request.query, 'returnUrl')\n\n if (!query) {\n return false\n }\n\n const params = {} as Record<string, FormStateValue | undefined>\n\n for (const [key, value = ''] of Object.entries(query)) {\n if (hiddenFieldNames.has(key)) {\n const lookupFunc = paramLookupFunctions[key]\n if (lookupFunc) {\n const res = await lookupFunc(value, model.services)\n // Store original value and result\n params[key] = value\n params[res.key] = res.value\n } else {\n params[key] = value\n }\n }\n }\n\n const formData = await page.getState(request)\n await page.mergeState(request, formData, params)\n\n return true\n}\n\n/**\n * Copies any potentially invalid state into the payload, and removes those values from state\n * NOTE - this method has a side-effect on 'context.state' and 'context.payload'\n * @param request - the form request\n * @param context - the form context\n */\nexport function copyNotYetValidatedState(\n request: FormContextRequest,\n context: FormContext\n) {\n const potentiallyInvalidState = context.state[STATE_NOT_YET_VALIDATED] as\n | Record<string, FormValue>\n | undefined\n if (!potentiallyInvalidState) {\n return\n }\n\n const originalPath = potentiallyInvalidState[CURRENT_PAGE_PATH_KEY]\n\n if (originalPath && originalPath === request.url.pathname) {\n context.payload = {\n ...context.payload,\n ...potentiallyInvalidState,\n [CURRENT_PAGE_PATH_KEY]: undefined\n }\n }\n}\n\n/**\n * Remove any temporary 'not yet validated' state now that it's been validated\n * @param state - the form state\n */\nexport function clearNotYetValidatedState(\n state: FormSubmissionState\n): FormSubmissionState {\n if (state[STATE_NOT_YET_VALIDATED]) {\n state[STATE_NOT_YET_VALIDATED] = undefined\n }\n return state\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/forms-engine-plugin",
3
- "version": "4.0.34",
3
+ "version": "4.0.36",
4
4
  "description": "Defra forms engine",
5
5
  "type": "module",
6
6
  "files": [
@@ -293,6 +293,58 @@ describe('DeclarationField', () => {
293
293
  )
294
294
  })
295
295
 
296
+ it('sets Nunjucks component to true when checked from save-anbd-exit', () => {
297
+ def = {
298
+ ...def,
299
+ hint: 'Please read and confirm the following'
300
+ } satisfies DeclarationFieldComponent
301
+
302
+ collection = new ComponentCollection([def], { model })
303
+ field = collection.fields[0]
304
+ const viewModel = field.getViewModel(getFormData(['true', 'unchecked']))
305
+
306
+ expect(viewModel).toEqual(
307
+ expect.objectContaining({
308
+ hint: {
309
+ text: 'Please read and confirm the following'
310
+ },
311
+ items: [
312
+ {
313
+ value: 'true',
314
+ text: 'I understand and agree',
315
+ checked: true
316
+ }
317
+ ]
318
+ })
319
+ )
320
+ })
321
+
322
+ it('sets Nunjucks component to false when unchecked from save-anbd-exit', () => {
323
+ def = {
324
+ ...def,
325
+ hint: 'Please read and confirm the following'
326
+ } satisfies DeclarationFieldComponent
327
+
328
+ collection = new ComponentCollection([def], { model })
329
+ field = collection.fields[0]
330
+ const viewModel = field.getViewModel(getFormData(['unchecked']))
331
+
332
+ expect(viewModel).toEqual(
333
+ expect.objectContaining({
334
+ hint: {
335
+ text: 'Please read and confirm the following'
336
+ },
337
+ items: [
338
+ {
339
+ value: 'true',
340
+ text: 'I understand and agree',
341
+ checked: false
342
+ }
343
+ ]
344
+ })
345
+ )
346
+ })
347
+
296
348
  it('sets Nunjucks component value when posted', () => {
297
349
  def = {
298
350
  ...def,
@@ -137,8 +137,12 @@ export class DeclarationField extends FormComponent {
137
137
  }
138
138
  }
139
139
 
140
+ const payloadValue = payload[this.name]
140
141
  const isChecked =
141
- payload[this.name] === 'true' || payload[this.name] === true
142
+ payloadValue === 'true' ||
143
+ payloadValue === true ||
144
+ (Array.isArray(payloadValue) && payloadValue.some((x) => x === 'true'))
145
+
142
146
  return {
143
147
  ...viewModel,
144
148
  hint: hint ? { text: hint } : undefined,
@@ -31,6 +31,9 @@ const globals = {
31
31
  export const VIEW_PATH = 'src/server/plugins/engine/views'
32
32
  export const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'
33
33
 
34
+ export const STATE_NOT_YET_VALIDATED = '__stateNotYetValidated'
35
+ export const CURRENT_PAGE_PATH_KEY = '__currentPagePath'
36
+
34
37
  export const prepareNunjucksEnvironment = function (
35
38
  env: Environment,
36
39
  pluginOptions: PluginOptions
@@ -48,6 +48,7 @@ import {
48
48
  createPage,
49
49
  type PageControllerClass
50
50
  } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'
51
+ import { copyNotYetValidatedState } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'
51
52
  import { validationOptions as opts } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'
52
53
  import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
53
54
  import {
@@ -401,6 +402,9 @@ export class FormModel {
401
402
  // Add paths for navigation
402
403
  this.assignPaths(context)
403
404
 
405
+ // Handle restoration of payload from say a 'save-and-exit' request
406
+ copyNotYetValidatedState(request, context)
407
+
404
408
  return context
405
409
  }
406
410
 
@@ -29,7 +29,10 @@ import {
29
29
  } from '~/src/server/plugins/engine/helpers.js'
30
30
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
31
31
  import { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'
32
- import { prefillStateFromQueryParameters } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'
32
+ import {
33
+ clearNotYetValidatedState,
34
+ prefillStateFromQueryParameters
35
+ } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'
33
36
  import {
34
37
  type AnyFormRequest,
35
38
  type FormContext,
@@ -325,7 +328,8 @@ export class QuestionPageController extends PageController {
325
328
 
326
329
  const cacheService = getCacheService(request.server)
327
330
 
328
- return cacheService.setState(request, state)
331
+ // Clear any 'not yet validated' state before saving to cache
332
+ return cacheService.setState(request, clearNotYetValidatedState(state))
329
333
  }
330
334
 
331
335
  async mergeState(
@@ -3,10 +3,15 @@ import { ComponentType, type Page } from '@defra/forms-model'
3
3
  import { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
4
4
  import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'
5
5
  import {
6
+ copyNotYetValidatedState,
6
7
  prefillStateFromQueryParameters,
7
8
  stripParam
8
9
  } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'
9
- import { type AnyFormRequest } from '~/src/server/plugins/engine/types.js'
10
+ import {
11
+ type AnyFormRequest,
12
+ type FormContext,
13
+ type FormContextRequest
14
+ } from '~/src/server/plugins/engine/types.js'
10
15
  import { type FormsService, type Services } from '~/src/server/types.js'
11
16
 
12
17
  function buildMockPage(
@@ -218,4 +223,73 @@ describe('State helpers', () => {
218
223
  expect(stripParam(params, 'anyParam')).toBeUndefined()
219
224
  })
220
225
  })
226
+
227
+ describe('copyNotYetValidatedState', () => {
228
+ it('should ignore if no invalid state', () => {
229
+ const mockRequest = {} as FormContextRequest
230
+ const mockContext = {
231
+ state: { abc: '123' },
232
+ payload: {}
233
+ } as unknown as FormContext
234
+ copyNotYetValidatedState(mockRequest, mockContext)
235
+ expect(mockContext.state).toEqual({ abc: '123' })
236
+ expect(mockContext.payload).toEqual({})
237
+ })
238
+
239
+ it('should ignore if wrong path', () => {
240
+ const mockRequest = {
241
+ url: {
242
+ pathname: '/form-page1'
243
+ }
244
+ } as unknown as FormContextRequest
245
+ const mockContext = {
246
+ state: {
247
+ abc: '123',
248
+ __stateNotYetValidated: {
249
+ def: '456',
250
+ __currentPagePath: '/root'
251
+ }
252
+ },
253
+ payload: {}
254
+ } as unknown as FormContext
255
+ copyNotYetValidatedState(mockRequest, mockContext)
256
+ expect(mockContext.state).toEqual({
257
+ abc: '123',
258
+ __stateNotYetValidated: {
259
+ def: '456',
260
+ __currentPagePath: '/root'
261
+ }
262
+ })
263
+ expect(mockContext.payload).toEqual({})
264
+ })
265
+
266
+ it('should apply if correct path', () => {
267
+ const mockRequest = {
268
+ url: {
269
+ pathname: '/form-page1'
270
+ }
271
+ } as unknown as FormContextRequest
272
+ const mockContext = {
273
+ state: {
274
+ abc: '123',
275
+ __stateNotYetValidated: {
276
+ def: '456',
277
+ __currentPagePath: '/form-page1'
278
+ }
279
+ },
280
+ payload: {}
281
+ } as unknown as FormContext
282
+ copyNotYetValidatedState(mockRequest, mockContext)
283
+ expect(mockContext.state).toEqual({
284
+ abc: '123',
285
+ __stateNotYetValidated: {
286
+ def: '456',
287
+ __currentPagePath: '/form-page1'
288
+ }
289
+ })
290
+ expect(mockContext.payload).toEqual({
291
+ def: '456'
292
+ })
293
+ })
294
+ })
221
295
  })
@@ -1,9 +1,17 @@
1
1
  import { getHiddenFields } from '@defra/forms-model'
2
2
 
3
+ import {
4
+ CURRENT_PAGE_PATH_KEY,
5
+ STATE_NOT_YET_VALIDATED
6
+ } from '~/src/server/plugins/engine/index.js'
3
7
  import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'
4
8
  import {
5
9
  type AnyFormRequest,
6
- type FormStateValue
10
+ type FormContext,
11
+ type FormContextRequest,
12
+ type FormStateValue,
13
+ type FormSubmissionState,
14
+ type FormValue
7
15
  } from '~/src/server/plugins/engine/types.js'
8
16
  import { type FormQuery } from '~/src/server/routes/types.js'
9
17
  import { type Services } from '~/src/server/types.js'
@@ -91,3 +99,44 @@ export async function prefillStateFromQueryParameters(
91
99
 
92
100
  return true
93
101
  }
102
+
103
+ /**
104
+ * Copies any potentially invalid state into the payload, and removes those values from state
105
+ * NOTE - this method has a side-effect on 'context.state' and 'context.payload'
106
+ * @param request - the form request
107
+ * @param context - the form context
108
+ */
109
+ export function copyNotYetValidatedState(
110
+ request: FormContextRequest,
111
+ context: FormContext
112
+ ) {
113
+ const potentiallyInvalidState = context.state[STATE_NOT_YET_VALIDATED] as
114
+ | Record<string, FormValue>
115
+ | undefined
116
+ if (!potentiallyInvalidState) {
117
+ return
118
+ }
119
+
120
+ const originalPath = potentiallyInvalidState[CURRENT_PAGE_PATH_KEY]
121
+
122
+ if (originalPath && originalPath === request.url.pathname) {
123
+ context.payload = {
124
+ ...context.payload,
125
+ ...potentiallyInvalidState,
126
+ [CURRENT_PAGE_PATH_KEY]: undefined
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Remove any temporary 'not yet validated' state now that it's been validated
133
+ * @param state - the form state
134
+ */
135
+ export function clearNotYetValidatedState(
136
+ state: FormSubmissionState
137
+ ): FormSubmissionState {
138
+ if (state[STATE_NOT_YET_VALIDATED]) {
139
+ state[STATE_NOT_YET_VALIDATED] = undefined
140
+ }
141
+ return state
142
+ }