@defra/forms-engine-plugin 4.5.6 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.server/server/plugins/engine/beta/form-context.js +1 -5
- package/.server/server/plugins/engine/beta/form-context.js.map +1 -1
- package/.server/server/plugins/engine/components/EmailAddressField.d.ts +2 -4
- package/.server/server/plugins/engine/components/EmailAddressField.js +5 -1
- package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +0 -2
- package/.server/server/plugins/engine/models/FormModel.js +1 -4
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +0 -4
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +1 -22
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/state.js +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/state.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +2 -0
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +0 -1
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/utils/utils.d.ts +6 -0
- package/.server/server/utils/utils.js +13 -0
- package/.server/server/utils/utils.js.map +1 -1
- package/.server/server/utils/utils.test.js +37 -1
- package/.server/server/utils/utils.test.js.map +1 -1
- package/package.json +2 -2
- package/src/server/plugins/engine/beta/form-context.test.ts +0 -2
- package/src/server/plugins/engine/beta/form-context.ts +1 -8
- package/src/server/plugins/engine/components/EmailAddressField.ts +16 -4
- package/src/server/plugins/engine/models/FormModel.test.ts +0 -64
- package/src/server/plugins/engine/models/FormModel.ts +1 -5
- package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +4 -356
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +1 -31
- package/src/server/plugins/engine/pageControllers/helpers/state.ts +1 -1
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +2 -0
- package/src/server/plugins/engine/types.ts +0 -1
- package/src/server/utils/utils.js +11 -0
- package/src/server/utils/utils.test.js +16 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Boom from '@hapi/boom';
|
|
2
2
|
import { isEqual } from 'date-fns';
|
|
3
3
|
import { PREVIEW_PATH_PREFIX } from "../../../constants.js";
|
|
4
|
-
import { checkEmailAddressForLiveFormSubmission, getCacheService
|
|
4
|
+
import { checkEmailAddressForLiveFormSubmission, getCacheService } from "../helpers.js";
|
|
5
5
|
import { FormModel } from "../models/index.js";
|
|
6
6
|
import { TerminalPageController } from "../pageControllers/index.js";
|
|
7
7
|
import * as defaultServices from "../services/index.js";
|
|
@@ -18,10 +18,8 @@ export async function getFormModel(slug, state, options = {}) {
|
|
|
18
18
|
if (!definition) {
|
|
19
19
|
throw Boom.notFound(`No definition found for form metadata ${metadata.id} (${slug}) ${state}`);
|
|
20
20
|
}
|
|
21
|
-
const versionNumber = getFormVersion(definition)?.versionNumber;
|
|
22
21
|
return new FormModel(definition, {
|
|
23
22
|
basePath: options.basePath ?? buildBasePath(options.routePrefix ?? '', slug, formState, isPreview),
|
|
24
|
-
versionNumber,
|
|
25
23
|
ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,
|
|
26
24
|
formId: options.formId ?? metadata.id
|
|
27
25
|
}, services, options.controllers);
|
|
@@ -83,10 +81,8 @@ export async function resolveFormModel(server, slug, state, options = {}) {
|
|
|
83
81
|
}
|
|
84
82
|
checkEmailAddressForLiveFormSubmission(metadata.notificationEmail, isPreview);
|
|
85
83
|
const routePrefix = options.routePrefix ?? server.realm.modifiers.route.prefix;
|
|
86
|
-
const versionNumber = getFormVersion(definition)?.versionNumber;
|
|
87
84
|
const model = new FormModel(definition, {
|
|
88
85
|
basePath: options.basePath ?? buildBasePath(routePrefix, slug, formState, isPreview),
|
|
89
|
-
versionNumber,
|
|
90
86
|
ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,
|
|
91
87
|
formId: options.formId ?? metadata.id
|
|
92
88
|
}, services, options.controllers);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-context.js","names":["Boom","isEqual","PREVIEW_PATH_PREFIX","checkEmailAddressForLiveFormSubmission","getCacheService","getFormVersion","FormModel","TerminalPageController","defaultServices","FormStatus","getFormModel","slug","state","options","services","formsService","isPreview","isPreviewState","formState","resolveState","metadata","getFormMetadata","definition","getFormDefinition","id","notFound","versionNumber","basePath","buildBasePath","routePrefix","ordnanceSurveyApiKey","formId","controllers","getFormContext","server","yar","Live","formModel","resolveFormModel","cacheService","summaryRequest","app","method","params","path","query","url","URL","cachedState","getState","$$__referenceNumber","errors","stateMetadata","models","Map","cache","cacheKey","entry","get","updatedAt","notificationEmail","realm","modifiers","route","prefix","model","set","base","replace","startsWith","slice","getFirstJourneyPage","context","relevantPages","undefined","lastPageReached","at","penultimatePageReached"],"sources":["../../../../../src/server/plugins/engine/beta/form-context.ts"],"sourcesContent":["import Boom from '@hapi/boom'\nimport { type Request, type Server } from '@hapi/hapi'\nimport { isEqual } from 'date-fns'\n\nimport { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n getCacheService,\n getFormVersion\n} from '~/src/server/plugins/engine/helpers.js'\nimport { FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { TerminalPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport {\n type AnyRequest,\n type FormContext,\n type FormContextRequest,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { FormStatus } from '~/src/server/routes/types.js'\nimport { type Services } from '~/src/server/types.js'\n\ntype JourneyState = FormStatus | 'preview'\n\nexport interface FormModelOptions {\n services?: Services\n controllers?: Record<string, typeof PageController>\n basePath?: string\n ordnanceSurveyApiKey?: string\n formId?: string\n routePrefix?: string\n isPreview?: boolean\n}\n\nexport interface FormContextOptions extends FormModelOptions {\n errors?: FormSubmissionError[]\n}\n\ntype SummaryRequest = FormContextRequest & {\n yar: Request['yar']\n}\n\nexport async function getFormModel(\n slug: string,\n state: JourneyState,\n options: FormModelOptions = {}\n) {\n const services = options.services ?? defaultServices\n const { formsService } = services\n const isPreview = isPreviewState(state, options)\n const formState = resolveState(state)\n\n const metadata = await formsService.getFormMetadata(slug)\n\n const definition = await formsService.getFormDefinition(\n metadata.id,\n formState\n )\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${metadata.id} (${slug}) ${state}`\n )\n }\n\n const versionNumber = getFormVersion(definition)?.versionNumber\n\n return new FormModel(\n definition,\n {\n basePath:\n options.basePath ??\n buildBasePath(options.routePrefix ?? '', slug, formState, isPreview),\n versionNumber,\n ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,\n formId: options.formId ?? metadata.id\n },\n services,\n options.controllers\n )\n}\n\nexport async function getFormContext(\n { server, yar }: Pick<Request, 'server' | 'yar'>,\n slug: string,\n state: JourneyState = FormStatus.Live,\n options: FormContextOptions = {}\n): Promise<FormContext> {\n const formModel = await resolveFormModel(server, slug, state, options)\n\n const cacheService = getCacheService(server)\n\n const summaryRequest: SummaryRequest = {\n app: {},\n method: 'get',\n params: {\n path: 'summary',\n slug,\n ...(isPreviewState(state, options) && {\n state: resolveState(state)\n })\n },\n path: `/${formModel.basePath}/summary`,\n query: {},\n url: new URL(\n `/${formModel.basePath}/summary`,\n 'https://form-context.local'\n ),\n server,\n yar\n }\n\n const cachedState = await cacheService.getState(\n summaryRequest as unknown as AnyRequest\n )\n\n const formState = {\n ...cachedState,\n $$__referenceNumber: cachedState.$$__referenceNumber\n } as unknown as FormSubmissionState\n\n return formModel.getFormContext(\n summaryRequest,\n formState,\n options.errors ?? []\n )\n}\n\nexport async function resolveFormModel(\n server: Server,\n slug: string,\n state: JourneyState,\n options: FormModelOptions = {}\n) {\n const services = options.services ?? defaultServices\n const { formsService } = services\n\n const metadata = await formsService.getFormMetadata(slug)\n const formState = resolveState(state)\n const isPreview = options.isPreview ?? isPreviewState(state, options)\n const stateMetadata = metadata[formState]\n\n if (!stateMetadata) {\n throw Boom.notFound(\n `No '${formState}' state for form metadata ${metadata.id}`\n )\n }\n\n // The models cache is created lazily per server instance\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!server.app.models) {\n server.app.models = new Map<string, { model: FormModel; updatedAt: Date }>()\n }\n\n const cache = server.app.models as Map<\n string,\n { model: FormModel; updatedAt: Date }\n >\n\n const cacheKey = `${metadata.id}_${formState}_${isPreview}`\n let entry = cache.get(cacheKey)\n\n if (!entry || !isEqual(entry.updatedAt, stateMetadata.updatedAt)) {\n const definition = await formsService.getFormDefinition(\n metadata.id,\n formState\n )\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${metadata.id} (${slug}) ${state}`\n )\n }\n\n checkEmailAddressForLiveFormSubmission(\n metadata.notificationEmail,\n isPreview\n )\n\n const routePrefix =\n options.routePrefix ?? server.realm.modifiers.route.prefix\n\n const versionNumber = getFormVersion(definition)?.versionNumber\n\n const model = new FormModel(\n definition,\n {\n basePath:\n options.basePath ??\n buildBasePath(routePrefix, slug, formState, isPreview),\n versionNumber,\n ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,\n formId: options.formId ?? metadata.id\n },\n services,\n options.controllers\n )\n\n entry = { model, updatedAt: stateMetadata.updatedAt }\n cache.set(cacheKey, entry)\n }\n\n return entry.model\n}\n\nfunction buildBasePath(\n routePrefix: string,\n slug: string,\n state: FormStatus,\n isPreview: boolean\n) {\n const base = (\n isPreview\n ? `${routePrefix}${PREVIEW_PATH_PREFIX}/${state}/${slug}`\n : `${routePrefix}/${slug}`\n ).replace(/\\/{2,}/g, '/')\n\n return base.startsWith('/') ? base.slice(1) : base\n}\n\nexport function getFirstJourneyPage(\n context?: Pick<FormContext, 'relevantPages'>\n) {\n if (!context?.relevantPages) {\n return undefined\n }\n\n const lastPageReached = context.relevantPages.at(-1)\n const penultimatePageReached = context.relevantPages.at(-2)\n\n if (\n lastPageReached instanceof TerminalPageController &&\n penultimatePageReached\n ) {\n return penultimatePageReached\n }\n\n return lastPageReached\n}\n\nfunction resolveState(state: JourneyState): FormStatus {\n return state === 'preview' ? FormStatus.Live : state\n}\n\nfunction isPreviewState(\n state: JourneyState,\n options: FormModelOptions = {}\n): boolean {\n return options.isPreview ?? state === 'preview'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"form-context.js","names":["Boom","isEqual","PREVIEW_PATH_PREFIX","checkEmailAddressForLiveFormSubmission","getCacheService","FormModel","TerminalPageController","defaultServices","FormStatus","getFormModel","slug","state","options","services","formsService","isPreview","isPreviewState","formState","resolveState","metadata","getFormMetadata","definition","getFormDefinition","id","notFound","basePath","buildBasePath","routePrefix","ordnanceSurveyApiKey","formId","controllers","getFormContext","server","yar","Live","formModel","resolveFormModel","cacheService","summaryRequest","app","method","params","path","query","url","URL","cachedState","getState","$$__referenceNumber","errors","stateMetadata","models","Map","cache","cacheKey","entry","get","updatedAt","notificationEmail","realm","modifiers","route","prefix","model","set","base","replace","startsWith","slice","getFirstJourneyPage","context","relevantPages","undefined","lastPageReached","at","penultimatePageReached"],"sources":["../../../../../src/server/plugins/engine/beta/form-context.ts"],"sourcesContent":["import Boom from '@hapi/boom'\nimport { type Request, type Server } from '@hapi/hapi'\nimport { isEqual } from 'date-fns'\n\nimport { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport { FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { TerminalPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport {\n type AnyRequest,\n type FormContext,\n type FormContextRequest,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { FormStatus } from '~/src/server/routes/types.js'\nimport { type Services } from '~/src/server/types.js'\n\ntype JourneyState = FormStatus | 'preview'\n\nexport interface FormModelOptions {\n services?: Services\n controllers?: Record<string, typeof PageController>\n basePath?: string\n ordnanceSurveyApiKey?: string\n formId?: string\n routePrefix?: string\n isPreview?: boolean\n}\n\nexport interface FormContextOptions extends FormModelOptions {\n errors?: FormSubmissionError[]\n}\n\ntype SummaryRequest = FormContextRequest & {\n yar: Request['yar']\n}\n\nexport async function getFormModel(\n slug: string,\n state: JourneyState,\n options: FormModelOptions = {}\n) {\n const services = options.services ?? defaultServices\n const { formsService } = services\n const isPreview = isPreviewState(state, options)\n const formState = resolveState(state)\n\n const metadata = await formsService.getFormMetadata(slug)\n\n const definition = await formsService.getFormDefinition(\n metadata.id,\n formState\n )\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${metadata.id} (${slug}) ${state}`\n )\n }\n\n return new FormModel(\n definition,\n {\n basePath:\n options.basePath ??\n buildBasePath(options.routePrefix ?? '', slug, formState, isPreview),\n ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,\n formId: options.formId ?? metadata.id\n },\n services,\n options.controllers\n )\n}\n\nexport async function getFormContext(\n { server, yar }: Pick<Request, 'server' | 'yar'>,\n slug: string,\n state: JourneyState = FormStatus.Live,\n options: FormContextOptions = {}\n): Promise<FormContext> {\n const formModel = await resolveFormModel(server, slug, state, options)\n\n const cacheService = getCacheService(server)\n\n const summaryRequest: SummaryRequest = {\n app: {},\n method: 'get',\n params: {\n path: 'summary',\n slug,\n ...(isPreviewState(state, options) && {\n state: resolveState(state)\n })\n },\n path: `/${formModel.basePath}/summary`,\n query: {},\n url: new URL(\n `/${formModel.basePath}/summary`,\n 'https://form-context.local'\n ),\n server,\n yar\n }\n\n const cachedState = await cacheService.getState(\n summaryRequest as unknown as AnyRequest\n )\n\n const formState = {\n ...cachedState,\n $$__referenceNumber: cachedState.$$__referenceNumber\n } as unknown as FormSubmissionState\n\n return formModel.getFormContext(\n summaryRequest,\n formState,\n options.errors ?? []\n )\n}\n\nexport async function resolveFormModel(\n server: Server,\n slug: string,\n state: JourneyState,\n options: FormModelOptions = {}\n) {\n const services = options.services ?? defaultServices\n const { formsService } = services\n\n const metadata = await formsService.getFormMetadata(slug)\n const formState = resolveState(state)\n const isPreview = options.isPreview ?? isPreviewState(state, options)\n const stateMetadata = metadata[formState]\n\n if (!stateMetadata) {\n throw Boom.notFound(\n `No '${formState}' state for form metadata ${metadata.id}`\n )\n }\n\n // The models cache is created lazily per server instance\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!server.app.models) {\n server.app.models = new Map<string, { model: FormModel; updatedAt: Date }>()\n }\n\n const cache = server.app.models as Map<\n string,\n { model: FormModel; updatedAt: Date }\n >\n\n const cacheKey = `${metadata.id}_${formState}_${isPreview}`\n let entry = cache.get(cacheKey)\n\n if (!entry || !isEqual(entry.updatedAt, stateMetadata.updatedAt)) {\n const definition = await formsService.getFormDefinition(\n metadata.id,\n formState\n )\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${metadata.id} (${slug}) ${state}`\n )\n }\n\n checkEmailAddressForLiveFormSubmission(\n metadata.notificationEmail,\n isPreview\n )\n\n const routePrefix =\n options.routePrefix ?? server.realm.modifiers.route.prefix\n\n const model = new FormModel(\n definition,\n {\n basePath:\n options.basePath ??\n buildBasePath(routePrefix, slug, formState, isPreview),\n ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,\n formId: options.formId ?? metadata.id\n },\n services,\n options.controllers\n )\n\n entry = { model, updatedAt: stateMetadata.updatedAt }\n cache.set(cacheKey, entry)\n }\n\n return entry.model\n}\n\nfunction buildBasePath(\n routePrefix: string,\n slug: string,\n state: FormStatus,\n isPreview: boolean\n) {\n const base = (\n isPreview\n ? `${routePrefix}${PREVIEW_PATH_PREFIX}/${state}/${slug}`\n : `${routePrefix}/${slug}`\n ).replace(/\\/{2,}/g, '/')\n\n return base.startsWith('/') ? base.slice(1) : base\n}\n\nexport function getFirstJourneyPage(\n context?: Pick<FormContext, 'relevantPages'>\n) {\n if (!context?.relevantPages) {\n return undefined\n }\n\n const lastPageReached = context.relevantPages.at(-1)\n const penultimatePageReached = context.relevantPages.at(-2)\n\n if (\n lastPageReached instanceof TerminalPageController &&\n penultimatePageReached\n ) {\n return penultimatePageReached\n }\n\n return lastPageReached\n}\n\nfunction resolveState(state: JourneyState): FormStatus {\n return state === 'preview' ? FormStatus.Live : state\n}\n\nfunction isPreviewState(\n state: JourneyState,\n options: FormModelOptions = {}\n): boolean {\n return options.isPreview ?? state === 'preview'\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -32,11 +32,9 @@ export declare class EmailAddressField extends FormComponent {
|
|
|
32
32
|
multiple?: string;
|
|
33
33
|
accept
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* For error preview page that shows all possible errors on a component
|
|
36
36
|
*/
|
|
37
|
-
|
|
38
|
-
* Static version of getAllPossibleErrors that doesn't require a component instance.
|
|
39
|
-
*/: string;
|
|
37
|
+
?: string;
|
|
40
38
|
inputmode?: string;
|
|
41
39
|
};
|
|
42
40
|
content?: import("./types.js").Content | import("./types.js").Content[] | string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { preventUnicodeInEmail } from '@defra/forms-model';
|
|
1
2
|
import joi from 'joi';
|
|
2
3
|
import { FormComponent } from "./FormComponent.js";
|
|
3
4
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
@@ -7,7 +8,7 @@ export class EmailAddressField extends FormComponent {
|
|
|
7
8
|
const {
|
|
8
9
|
options
|
|
9
10
|
} = def;
|
|
10
|
-
let formSchema = joi.string().email().
|
|
11
|
+
let formSchema = joi.string().trim().email().custom((value, helpers) => preventUnicodeInEmail(value, helpers)).label(this.label).required();
|
|
11
12
|
if (options.required === false) {
|
|
12
13
|
formSchema = formSchema.allow('');
|
|
13
14
|
}
|
|
@@ -55,6 +56,9 @@ export class EmailAddressField extends FormComponent {
|
|
|
55
56
|
}, {
|
|
56
57
|
type: 'format',
|
|
57
58
|
template: messageTemplate.format
|
|
59
|
+
}, {
|
|
60
|
+
type: 'unicode',
|
|
61
|
+
template: messageTemplate.unicode
|
|
58
62
|
}],
|
|
59
63
|
advancedSettingsErrors: []
|
|
60
64
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailAddressField.js","names":["joi","FormComponent","messageTemplate","EmailAddressField","constructor","def","props","options","formSchema","string","email","
|
|
1
|
+
{"version":3,"file":"EmailAddressField.js","names":["preventUnicodeInEmail","joi","FormComponent","messageTemplate","EmailAddressField","constructor","def","props","options","formSchema","string","trim","email","custom","value","helpers","label","required","allow","customValidationMessage","message","messages","customValidationMessages","default","stateSchema","getViewModel","payload","errors","viewModel","attributes","autocomplete","type","getAllPossibleErrors","baseErrors","template","format","unicode","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/EmailAddressField.ts"],"sourcesContent":["import {\n preventUnicodeInEmail,\n type EmailAddressFieldComponent\n} from '@defra/forms-model'\nimport joi, { type CustomHelpers } from 'joi'\n\nimport { FormComponent } 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 FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nexport class EmailAddressField extends FormComponent {\n declare options: EmailAddressFieldComponent['options']\n\n constructor(\n def: EmailAddressFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options } = def\n\n let formSchema = joi\n .string()\n .trim()\n .email()\n .custom((value, helpers: CustomHelpers<string>) =>\n preventUnicodeInEmail(value, helpers)\n )\n .label(this.label)\n .required()\n\n if (options.required === false) {\n formSchema = formSchema.allow('')\n }\n\n if (options.customValidationMessage) {\n const message = options.customValidationMessage\n\n formSchema = formSchema.messages({\n 'any.required': message,\n 'string.empty': message,\n 'string.email': message\n })\n } else if (options.customValidationMessages) {\n formSchema = formSchema.messages(options.customValidationMessages)\n }\n\n this.formSchema = formSchema.default('')\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = options\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n const { attributes } = viewModel\n\n attributes.autocomplete = 'email'\n\n return {\n ...viewModel,\n type: 'email'\n }\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return EmailAddressField.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.required },\n { type: 'format', template: messageTemplate.format },\n { type: 'unicode', template: messageTemplate.unicode }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AAAA,SACEA,qBAAqB,QAEhB,oBAAoB;AAC3B,OAAOC,GAAG,MAA8B,KAAK;AAE7C,SAASC,aAAa;AACtB,SAASC,eAAe;AAOxB,OAAO,MAAMC,iBAAiB,SAASF,aAAa,CAAC;EAGnDG,WAAWA,CACTC,GAA+B,EAC/BC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEC;IAAQ,CAAC,GAAGF,GAAG;IAEvB,IAAIG,UAAU,GAAGR,GAAG,CACjBS,MAAM,CAAC,CAAC,CACRC,IAAI,CAAC,CAAC,CACNC,KAAK,CAAC,CAAC,CACPC,MAAM,CAAC,CAACC,KAAK,EAAEC,OAA8B,KAC5Cf,qBAAqB,CAACc,KAAK,EAAEC,OAAO,CACtC,CAAC,CACAC,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC,CACjBC,QAAQ,CAAC,CAAC;IAEb,IAAIT,OAAO,CAACS,QAAQ,KAAK,KAAK,EAAE;MAC9BR,UAAU,GAAGA,UAAU,CAACS,KAAK,CAAC,EAAE,CAAC;IACnC;IAEA,IAAIV,OAAO,CAACW,uBAAuB,EAAE;MACnC,MAAMC,OAAO,GAAGZ,OAAO,CAACW,uBAAuB;MAE/CV,UAAU,GAAGA,UAAU,CAACY,QAAQ,CAAC;QAC/B,cAAc,EAAED,OAAO;QACvB,cAAc,EAAEA,OAAO;QACvB,cAAc,EAAEA;MAClB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAIZ,OAAO,CAACc,wBAAwB,EAAE;MAC3Cb,UAAU,GAAGA,UAAU,CAACY,QAAQ,CAACb,OAAO,CAACc,wBAAwB,CAAC;IACpE;IAEA,IAAI,CAACb,UAAU,GAAGA,UAAU,CAACc,OAAO,CAAC,EAAE,CAAC;IACxC,IAAI,CAACC,WAAW,GAAGf,UAAU,CAACc,OAAO,CAAC,IAAI,CAAC,CAACL,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,CAACV,OAAO,GAAGA,OAAO;EACxB;EAEAiB,YAAYA,CAACC,OAAoB,EAAEC,MAA8B,EAAE;IACjE,MAAMC,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,EAAEC,MAAM,CAAC;IACrD,MAAM;MAAEE;IAAW,CAAC,GAAGD,SAAS;IAEhCC,UAAU,CAACC,YAAY,GAAG,OAAO;IAEjC,OAAO;MACL,GAAGF,SAAS;MACZG,IAAI,EAAE;IACR,CAAC;EACH;;EAEA;AACF;AACA;EACEC,oBAAoBA,CAAA,EAA6B;IAC/C,OAAO5B,iBAAiB,CAAC4B,oBAAoB,CAAC,CAAC;EACjD;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QAAEF,IAAI,EAAE,UAAU;QAAEG,QAAQ,EAAE/B,eAAe,CAACc;MAAS,CAAC,EACxD;QAAEc,IAAI,EAAE,QAAQ;QAAEG,QAAQ,EAAE/B,eAAe,CAACgC;MAAO,CAAC,EACpD;QAAEJ,IAAI,EAAE,SAAS;QAAEG,QAAQ,EAAE/B,eAAe,CAACiC;MAAQ,CAAC,CACvD;MACDC,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -19,7 +19,6 @@ export declare class FormModel {
|
|
|
19
19
|
formId: string;
|
|
20
20
|
values: FormDefinition;
|
|
21
21
|
basePath: string;
|
|
22
|
-
versionNumber?: number;
|
|
23
22
|
ordnanceSurveyApiKey?: string;
|
|
24
23
|
conditions: Partial<Record<string, ExecutableCondition>>;
|
|
25
24
|
pages: PageControllerClass[];
|
|
@@ -34,7 +33,6 @@ export declare class FormModel {
|
|
|
34
33
|
componentMap: Map<string, Component>;
|
|
35
34
|
constructor(def: typeof this.def, options: {
|
|
36
35
|
basePath: string;
|
|
37
|
-
versionNumber?: number;
|
|
38
36
|
ordnanceSurveyApiKey?: string;
|
|
39
37
|
formId?: string;
|
|
40
38
|
}, services?: Services, controllers?: Record<string, typeof PageController>);
|
|
@@ -26,7 +26,6 @@ export class FormModel {
|
|
|
26
26
|
formId;
|
|
27
27
|
values;
|
|
28
28
|
basePath;
|
|
29
|
-
versionNumber;
|
|
30
29
|
ordnanceSurveyApiKey;
|
|
31
30
|
conditions;
|
|
32
31
|
pages;
|
|
@@ -84,7 +83,6 @@ export class FormModel {
|
|
|
84
83
|
this.formId = options.formId ?? '';
|
|
85
84
|
this.values = result.value;
|
|
86
85
|
this.basePath = options.basePath;
|
|
87
|
-
this.versionNumber = options.versionNumber;
|
|
88
86
|
this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey;
|
|
89
87
|
this.conditions = {};
|
|
90
88
|
this.services = services;
|
|
@@ -232,8 +230,7 @@ export class FormModel {
|
|
|
232
230
|
componentDefMap: this.componentDefMap,
|
|
233
231
|
pageMap: this.pageMap,
|
|
234
232
|
componentMap: this.componentMap,
|
|
235
|
-
referenceNumber: getReferenceNumber(state)
|
|
236
|
-
submittedVersionNumber: this.versionNumber
|
|
233
|
+
referenceNumber: getReferenceNumber(state)
|
|
237
234
|
};
|
|
238
235
|
|
|
239
236
|
// Validate current page
|
|
@@ -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","validationOptions","opts","defaultServices","FormAction","merge","logger","FormModel","engine","schemaVersion","def","lists","sections","name","formId","values","basePath","ordnanceSurveyApiKey","conditions","pages","services","controllers","pageDefMap","listDefMap","listDefIdMap","componentDefMap","componentDefIdMap","pageMap","componentMap","constructor","options","schema","V1","warn","result","validate","abortEarly","error","structuredClone","value","push","id","title","type","items","text","Map","map","page","path","list","filter","flatMap","components","component","forEach","conditionDef","condition","makeCondition","pageDef","some","controller","Status","collection","makeFilteredSchema","relevantPages","object","required","concat","stateSchema","parser","operators","logical","Object","assign","functions","dateForComparison","timePeriod","timeUnit","displayName","expr","toConditionExpression","fn","evaluationState","ctx","toConditionContext","evaluate","context","conditionId","propertyName","V2","defineProperty","get","from","parse","toExpression","getList","nameOrId","find","getSection","section","getFormContext","request","state","errors","query","currentPath","startPath","getStartPath","isForceAccess","relevantState","payload","getFormDataFromState","paths","data","referenceNumber","getReferenceNumber","validateFormPayload","nextPage","initialiseContext","assignEvaluationState","assignRelevantState","pageStateIsInvalid","getNextPath","validateFormState","assignPaths","emptyState","freeze","getContextValueFromState","key","keys","listFields","fields","field","undefined","YesNoField","hasOptionalItems","item","length","fieldStateIsInvalid","validValues","fieldState","getFormValueFromState","isInvalid","isArray","Array","every","includes","href","getComponentById","componentId","getListById","listId","getConditionById","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 ordnanceSurveyApiKey?: string\n conditions: Partial<Record<string, ExecutableCondition>>\n pages: PageControllerClass[]\n services: Services\n\n controllers?: Record<string, typeof PageController>\n pageDefMap: Map<string, Page>\n\n listDefMap: Map<string, List>\n listDefIdMap: Map<string, List>\n\n componentDefMap: Map<string, ComponentDef>\n componentDefIdMap: Map<string, ComponentDef>\n\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n\n constructor(\n def: typeof this.def,\n options: {\n basePath: string\n ordnanceSurveyApiKey?: string\n formId?: string\n },\n services: Services = defaultServices,\n controllers?: Record<string, typeof PageController>\n ) {\n let schema = formDefinitionV2Schema\n\n if (!def.schema || def.schema === SchemaVersion.V1) {\n logger.warn(\n `[DEPRECATION NOTICE] Form \"${def.name}\" constructed with legacy V1 schema. See https://defra.github.io/forms-engine-plugin/schemas/form-definition-schema.html.`\n )\n schema = formDefinitionSchema\n }\n\n const result = schema.validate(def, { abortEarly: false })\n\n if (result.error) {\n throw result.error\n }\n\n // Make a clone of the shallow copy returned\n // by joi so as not to change the source data.\n def = structuredClone(result.value)\n\n // Add default lists\n def.lists.push({\n id: def.schema === SchemaVersion.V1 ? yesNoListName : yesNoListId,\n name: '__yesNo',\n title: 'Yes/No',\n type: 'boolean',\n items: [\n {\n id: '02900d42-83d1-4c72-a719-c4e8228952fa',\n text: 'Yes',\n value: true\n },\n {\n id: 'f39000eb-c51b-4019-8f82-bbda0423f04d',\n text: 'No',\n value: false\n }\n ]\n })\n\n // Fix up page titles\n setPageTitles(def)\n\n this.engine = def.engine\n this.schemaVersion = def.schema ?? SchemaVersion.V1\n this.def = def\n this.lists = def.lists\n this.sections = def.sections\n this.name = def.name ?? ''\n this.formId = options.formId ?? ''\n this.values = result.value\n this.basePath = options.basePath\n this.ordnanceSurveyApiKey = options.ordnanceSurveyApiKey\n this.conditions = {}\n this.services = services\n this.controllers = controllers\n\n this.pageDefMap = new Map(def.pages.map((page) => [page.path, page]))\n this.listDefMap = new Map(def.lists.map((list) => [list.name, list]))\n this.listDefIdMap = new Map(\n def.lists\n .filter((list) => list.id) // Skip lists without an ID\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n .map((list) => [list.id as string, list])\n )\n this.componentDefMap = new Map(\n def.pages\n .filter(hasComponents)\n .flatMap((page) =>\n page.components.map((component) => [component.name, component])\n )\n )\n this.componentDefIdMap = new Map(\n def.pages.filter(hasComponents).flatMap((page) =>\n page.components\n .filter((component) => component.id) // Skip components without an ID\n .map((component) => {\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return [component.id as string, component]\n })\n )\n )\n\n def.conditions.forEach((conditionDef) => {\n const condition = this.makeCondition(\n isConditionWrapperV2(conditionDef)\n ? convertConditionWrapperFromV2(conditionDef, this)\n : conditionDef\n )\n this.conditions[condition.name] = condition\n })\n\n this.pages = def.pages.map((pageDef) => createPage(this, pageDef))\n\n if (\n !def.pages.some(\n ({ controller }) =>\n // Check for user-provided status page (optional)\n controller === ControllerType.Status\n )\n ) {\n this.pages.push(\n createPage(this, {\n title: 'Form submitted',\n path: ControllerPath.Status,\n controller: ControllerType.Status\n })\n )\n }\n\n this.pageMap = new Map(this.pages.map((page) => [page.path, page]))\n this.componentMap = new Map(\n this.pages.flatMap((page) =>\n page.collection.components.map((component) => [\n component.name,\n component\n ])\n )\n )\n }\n\n /**\n * build the entire model schema from individual pages/sections and filter out answers\n * for pages which are no longer accessible due to an answer that has been changed\n */\n makeFilteredSchema(relevantPages: PageControllerClass[]) {\n // Build the entire model schema\n // from the individual pages/sections\n let schema = joi.object<FormSubmissionState>().required()\n\n relevantPages.forEach((page) => {\n schema = schema.concat(page.collection.stateSchema)\n })\n\n return schema\n }\n\n /**\n * Instantiates a Condition based on {@link ConditionWrapper}\n * @param condition\n */\n makeCondition(condition: ConditionWrapper): ExecutableCondition {\n const parser = new Parser({\n operators: {\n logical: true\n }\n })\n\n Object.assign(parser.functions, {\n dateForComparison(timePeriod: number, timeUnit: DateUnits) {\n // The time element must be stripped (hence using startOfDay() which has no time element),\n // then formatted as YYYY-MM-DD otherwise we can hit time element and BST issues giving the\n // wrong date to compare against.\n // Do not use .toISOString() to format the date as that introduces BST errors.\n return format(\n add(todayAsDateOnly(), { [timeUnit]: timePeriod }),\n 'yyyy-MM-dd'\n )\n }\n })\n\n const { name, displayName, value } = condition\n const expr = this.toConditionExpression(value, parser)\n\n const fn = (evaluationState: FormState) => {\n const ctx = this.toConditionContext(evaluationState, this.conditions)\n try {\n return expr.evaluate(ctx) as boolean\n } catch {\n return false\n }\n }\n\n return {\n name,\n displayName,\n value,\n expr,\n fn\n }\n }\n\n toConditionContext(\n evaluationState: FormState,\n conditions: Partial<Record<string, ExecutableCondition>>\n ) {\n const context = { ...evaluationState }\n\n for (const conditionId in conditions) {\n const propertyName =\n this.schemaVersion === SchemaVersion.V2\n ? generateConditionAlias(conditionId)\n : conditionId\n\n Object.defineProperty(context, propertyName, {\n get() {\n return conditions[conditionId]?.fn(evaluationState)\n }\n })\n }\n\n return context as Extract<Value, Record<string, Value>>\n }\n\n toConditionExpression(value: ConditionsModelData, parser: Parser) {\n const conditions = ConditionsModel.from(value)\n return parser.parse(conditions.toExpression())\n }\n\n getList(nameOrId: string): List | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.lists.find((list) => list.name === nameOrId)\n : this.lists.find((list) => list.id === nameOrId)\n }\n\n getSection(nameOrId: string): Section | undefined {\n return this.schemaVersion === SchemaVersion.V1\n ? this.sections.find((section) => section.name === nameOrId)\n : this.sections.find((section) => section.id === nameOrId)\n }\n\n /**\n * Form context for the current page\n */\n getFormContext(\n request: FormContextRequest,\n state: FormSubmissionState,\n errors?: FormSubmissionError[]\n ): FormContext {\n const { query } = request\n\n const page = getPage(this, request)\n\n // Determine form paths\n const currentPath = page.path\n const startPath = page.getStartPath()\n\n // Preview URL direct access is allowed\n const isForceAccess = 'force' in query\n\n let context: FormContext = {\n evaluationState: {},\n relevantState: {},\n relevantPages: [],\n payload: page.getFormDataFromState(request, state),\n state,\n paths: [],\n errors,\n isForceAccess,\n data: {},\n pageDefMap: this.pageDefMap,\n listDefMap: this.listDefMap,\n componentDefMap: this.componentDefMap,\n pageMap: this.pageMap,\n componentMap: this.componentMap,\n referenceNumber: getReferenceNumber(state)\n }\n\n // Validate current page\n context = validateFormPayload(request, page, context)\n\n // Find start page\n let nextPage = findPage(this, startPath)\n\n this.initialiseContext(context)\n\n // Walk form pages from start\n while (nextPage) {\n // Add page to context\n context.relevantPages.push(nextPage)\n\n this.assignEvaluationState(context, nextPage)\n\n this.assignRelevantState(context, nextPage)\n\n // Stop at current page\n if (\n this.pageStateIsInvalid(context, nextPage) ||\n nextPage.path === currentPath\n ) {\n break\n }\n\n // Apply conditions to determine next page\n nextPage = findPage(this, nextPage.getNextPath(context))\n }\n\n // Validate form state\n context = validateFormState(request, page, context)\n\n // Add paths for navigation\n this.assignPaths(context)\n\n return context\n }\n\n private initialiseContext(context: FormContext) {\n // Initialise `evaluationState` for all keys using empty state.\n // This is because the current condition evaluation library (eval-expr)\n // will throw if an expression uses a key that is undefined.\n const emptyState = Object.freeze({})\n\n for (const page of this.pages) {\n const { collection, pageDef } = page\n\n if (!hasRepeater(pageDef)) {\n Object.assign(\n context.evaluationState,\n collection.getContextValueFromState(emptyState)\n )\n }\n }\n }\n\n private assignEvaluationState(\n context: FormContext,\n page: PageControllerClass\n ) {\n const { collection, pageDef } = page\n // Skip evaluation state for repeater pages\n\n if (!hasRepeater(pageDef)) {\n Object.assign(\n context.evaluationState,\n collection.getContextValueFromState(context.state)\n )\n }\n }\n\n private assignRelevantState(context: FormContext, page: PageControllerClass) {\n // Copy relevant state by expected keys\n for (const key of page.keys) {\n if (typeof context.state[key] !== 'undefined') {\n context.relevantState[key] = context.state[key]\n }\n }\n }\n\n private pageStateIsInvalid(context: FormContext, page: PageControllerClass) {\n // Get any list-bound fields on the page\n const listFields = page.collection.fields.filter(hasListFormField)\n\n // For each list field that is bound to a list that contains any conditional items,\n // we need to check any answers are still valid. Do this by evaluating the conditions\n // and ensuring any current answers are all included in the set of valid answers\n for (const field of listFields) {\n const list = field.list\n\n // Filter out YesNo as they can't be conditional\n if (list !== undefined && field.type !== ComponentType.YesNoField) {\n const hasOptionalItems =\n list.items.filter((item) => item.condition).length > 0\n\n if (hasOptionalItems) {\n return this.fieldStateIsInvalid(context, field, list)\n }\n }\n }\n }\n\n private fieldStateIsInvalid(\n context: FormContext,\n field: ListFormComponent,\n list: List\n ) {\n const { evaluationState, state } = context\n\n const validValues = list.items\n .filter((item) =>\n item.condition\n ? this.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n .map((item) => item.value)\n\n // Get the field state\n const fieldState = field.getFormValueFromState(state)\n\n if (fieldState !== undefined) {\n let isInvalid = false\n const isArray = Array.isArray(fieldState)\n\n // Check if any saved state value(s) are still valid\n // and return true if any are invalid\n if (isArray) {\n isInvalid = !fieldState.every((item) => validValues.includes(item))\n } else {\n isInvalid = !validValues.includes(fieldState)\n }\n\n if (isInvalid) {\n context.errors ??= []\n\n const text =\n 'Options are different because you changed a previous answer'\n\n context.errors.push({\n text,\n name: field.name,\n href: `#${field.name}`,\n path: [`#${field.name}`]\n })\n }\n\n return isInvalid\n }\n }\n\n private assignPaths(context: FormContext) {\n for (const { keys, path } of context.relevantPages) {\n context.paths.push(path)\n\n // Stop at page with errors\n if (\n context.errors?.some(({ name, path }) => {\n return keys.includes(name) || keys.some((key) => path.includes(key))\n })\n ) {\n break\n }\n }\n }\n\n getComponentById(componentId: string): ComponentDef | undefined {\n return this.componentDefIdMap.get(componentId)\n }\n\n getListById(listId: string): List | undefined {\n return this.listDefIdMap.get(listId)\n }\n\n /**\n * Returns a condition by its ID. O(n) lookup time.\n * @param conditionId\n * @returns\n */\n getConditionById(conditionId: string): ConditionWrapperV2 | undefined {\n return this.def.conditions\n .filter(isConditionWrapperV2)\n .find((condition) => condition.id === conditionId)\n }\n}\n\n/**\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":[]}
|
|
@@ -4,7 +4,3 @@ import { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
|
4
4
|
import { type DetailItem } from '~/src/server/plugins/engine/models/types.js';
|
|
5
5
|
import { type FormContext } from '~/src/server/plugins/engine/types.js';
|
|
6
6
|
export declare function format(context: FormContext, items: DetailItem[], model: FormModel, submitResponse: SubmitResponsePayload, formStatus: ReturnType<typeof checkFormStatus>, formMetadata?: FormMetadata): string;
|
|
7
|
-
export declare function getVersionMetadata(submittedVersionNumber: number | undefined, formMetadata?: FormMetadata): {
|
|
8
|
-
versionNumber: number;
|
|
9
|
-
createdAt: Date;
|
|
10
|
-
} | undefined;
|
|
@@ -7,7 +7,7 @@ export function format(context, items, model, submitResponse, formStatus, formMe
|
|
|
7
7
|
main: v2Main,
|
|
8
8
|
...v2Data
|
|
9
9
|
} = categoriseData(items);
|
|
10
|
-
const versionMetadata = getFormVersion(model.def)
|
|
10
|
+
const versionMetadata = getFormVersion(model.def);
|
|
11
11
|
const meta = {
|
|
12
12
|
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
13
13
|
timestamp: new Date(),
|
|
@@ -42,27 +42,6 @@ export function format(context, items, model, submitResponse, formStatus, formMe
|
|
|
42
42
|
};
|
|
43
43
|
return JSON.stringify(payload);
|
|
44
44
|
}
|
|
45
|
-
export function getVersionMetadata(submittedVersionNumber, formMetadata) {
|
|
46
|
-
if (!formMetadata?.versions?.length) {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
if (submittedVersionNumber !== undefined) {
|
|
50
|
-
const submittedVersion = formMetadata.versions.find(v => v.versionNumber === submittedVersionNumber);
|
|
51
|
-
if (submittedVersion) {
|
|
52
|
-
return {
|
|
53
|
-
versionNumber: submittedVersion.versionNumber,
|
|
54
|
-
createdAt: submittedVersion.createdAt
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// fallback to first available version
|
|
60
|
-
const firstVersion = formMetadata.versions[0];
|
|
61
|
-
return {
|
|
62
|
-
versionNumber: firstVersion.versionNumber,
|
|
63
|
-
createdAt: firstVersion.createdAt
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
45
|
function extractCsvFiles(submitResponse) {
|
|
67
46
|
const result = submitResponse.result;
|
|
68
47
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","
|
|
1
|
+
{"version":3,"file":"v1.js","names":["getFormVersion","categoriseData","FormAdapterSubmissionSchemaVersion","format","context","items","model","submitResponse","formStatus","formMetadata","csvFiles","extractCsvFiles","main","v2Main","v2Data","versionMetadata","def","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","state","isPreview","notificationEmail","Object","fromEntries","entries","map","key","value","undefined","data","result","files","payload","JSON","stringify","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport {\n getFormVersion,\n type checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { categoriseData } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const csvFiles = extractCsvFiles(submitResponse)\n\n const { main: v2Main, ...v2Data } = categoriseData(items)\n\n const versionMetadata = getFormVersion(model.def)\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.state,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? ''\n }\n\n if (versionMetadata) {\n meta.versionMetadata = versionMetadata\n }\n\n const main = Object.fromEntries(\n Object.entries(v2Main).map(([key, value]) => {\n if (value === undefined) {\n return [key, null]\n }\n\n return [key, value]\n })\n )\n\n const data: FormAdapterSubmissionMessageData = {\n main,\n ...v2Data\n }\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAKA,SACEA,cAAc;AAKhB,SAASC,cAAc;AACvB,SAASC,kCAAkC;AAS3C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,QAAQ,GAAGC,eAAe,CAACJ,cAAc,CAAC;EAEhD,MAAM;IAAEK,IAAI,EAAEC,MAAM;IAAE,GAAGC;EAAO,CAAC,GAAGb,cAAc,CAACI,KAAK,CAAC;EAEzD,MAAMU,eAAe,GAAGf,cAAc,CAACM,KAAK,CAACU,GAAG,CAAC;EAEjD,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEhB,kCAAkC,CAACiB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAElB,OAAO,CAACkB,eAAe;IACxCC,QAAQ,EAAEjB,KAAK,CAACkB,IAAI;IACpBC,MAAM,EAAEhB,YAAY,EAAEiB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAElB,YAAY,EAAEmB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAErB,UAAU,CAACsB,KAAK;IACxBC,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BC,iBAAiB,EAAEvB,YAAY,EAAEuB,iBAAiB,IAAI;EACxD,CAAC;EAED,IAAIjB,eAAe,EAAE;IACnBE,IAAI,CAACF,eAAe,GAAGA,eAAe;EACxC;EAEA,MAAMH,IAAI,GAAGqB,MAAM,CAACC,WAAW,CAC7BD,MAAM,CAACE,OAAO,CAACtB,MAAM,CAAC,CAACuB,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC3C,IAAIA,KAAK,KAAKC,SAAS,EAAE;MACvB,OAAO,CAACF,GAAG,EAAE,IAAI,CAAC;IACpB;IAEA,OAAO,CAACA,GAAG,EAAEC,KAAK,CAAC;EACrB,CAAC,CACH,CAAC;EAED,MAAME,IAAsC,GAAG;IAC7C5B,IAAI;IACJ,GAAGE;EACL,CAAC;EAED,MAAM2B,MAA0C,GAAG;IACjDC,KAAK,EAAEhC;EACT,CAAC;EAED,MAAMiC,OAA4C,GAAG;IACnD1B,IAAI;IACJuB,IAAI;IACJC;EACF,CAAC;EAED,OAAOG,IAAI,CAACC,SAAS,CAACF,OAAO,CAAC;AAChC;AAEA,SAAShC,eAAeA,CACtBJ,cAAqC,EACQ;EAC7C,MAAMkC,MAAM,GACVlC,cAAc,CAACkC,MAAqD;EAEtE,OAAO;IACL7B,IAAI,EAAE6B,MAAM,CAACC,KAAK,EAAE9B,IAAI,IAAI,EAAE;IAC9BkC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ControllerType, getHiddenFields } from '@defra/forms-model';
|
|
2
|
-
import { validate as isValidUUID } from 'uuid';
|
|
3
2
|
import { getCacheService } from "../../helpers.js";
|
|
4
3
|
import { CURRENT_PAGE_PATH_KEY, STATE_NOT_YET_VALIDATED } from "../../index.js";
|
|
4
|
+
import { isValidUUID } from "../../../../utils/utils.js";
|
|
5
5
|
const GUID_LENGTH = 36;
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","names":["ControllerType","getHiddenFields","
|
|
1
|
+
{"version":3,"file":"state.js","names":["ControllerType","getHiddenFields","getCacheService","CURRENT_PAGE_PATH_KEY","STATE_NOT_YET_VALIDATED","isValidUUID","GUID_LENGTH","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","checkSaveAndExitRepeater","context","potentiallyInvalidState","state","originalPath","repeaterPaths","pages","filter","controller","Repeat","p","basePath","path","segments","split","lastSegment","at","guidStartIndex","originalPathWithoutGuid","substring","includes","copyNotYetValidatedState","url","pathname","payload","cacheService","server","setState"],"sources":["../../../../../../src/server/plugins/engine/pageControllers/helpers/state.ts"],"sourcesContent":["import { ControllerType, getHiddenFields } from '@defra/forms-model'\n\nimport { getCacheService } from '~/src/server/plugins/engine/helpers.js'\nimport {\n CURRENT_PAGE_PATH_KEY,\n STATE_NOT_YET_VALIDATED\n} from '~/src/server/plugins/engine/index.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormStateValue,\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'\nimport { isValidUUID } from '~/src/server/utils/utils.js'\n\nconst GUID_LENGTH = 36\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 * Checks whether the save-and-exit finished on a repeater with partial state\n * @param context - the form context\n */\nexport function checkSaveAndExitRepeater(\n context: FormContext,\n model: FormModel\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 const repeaterPaths = model.def.pages\n .filter((page) => page.controller === ControllerType.Repeat)\n .map((p) => `/${model.basePath}${p.path}/`)\n\n if (typeof originalPath !== 'string') {\n return undefined\n }\n\n const segments = originalPath.split('/')\n const lastSegment = segments.at(-1) ?? ''\n\n if (!isValidUUID(lastSegment)) {\n return undefined\n }\n\n const guidStartIndex = originalPath.length - GUID_LENGTH\n const originalPathWithoutGuid = originalPath.substring(0, guidStartIndex)\n\n if (!repeaterPaths.includes(originalPathWithoutGuid)) {\n return undefined\n }\n\n return originalPath\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 async function copyNotYetValidatedState(\n request: AnyFormRequest,\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 // Remove any temporary 'not yet validated' state now it's been copied to the payload\n if (context.state[STATE_NOT_YET_VALIDATED]) {\n context.state[STATE_NOT_YET_VALIDATED] = undefined\n }\n\n const cacheService = getCacheService(request.server)\n await cacheService.setState(request, context.state)\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -21,6 +21,7 @@ export const messageTemplate = {
|
|
|
21
21
|
minMax: '{{#label}} must be between {{#min}} and {{#max}} characters',
|
|
22
22
|
pattern: joi.expression('Enter a valid {{lowerFirst(#label)}}', opts),
|
|
23
23
|
format: joi.expression('Enter {{lowerFirst(#label)}} in the correct format', opts),
|
|
24
|
+
unicode: '{{#label}} includes invalid characters, for example, long dashes',
|
|
24
25
|
number: '{{#label}} must be a number',
|
|
25
26
|
numberPrecision: '{{#label}} must have {{#limit}} or fewer decimal places',
|
|
26
27
|
numberInteger: '{{#label}} must be a whole number',
|
|
@@ -41,6 +42,7 @@ export const messages = {
|
|
|
41
42
|
'string.empty': messageTemplate.required,
|
|
42
43
|
'string.max': messageTemplate.max,
|
|
43
44
|
'string.email': messageTemplate.format,
|
|
45
|
+
'string.unicode': messageTemplate.unicode,
|
|
44
46
|
'string.pattern.base': messageTemplate.pattern,
|
|
45
47
|
'string.maxWords': messageTemplate.maxWords,
|
|
46
48
|
'number.base': messageTemplate.number,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validationOptions.js","names":["joi","lowerFirstPreserveProperNouns","opts","functions","lowerFirst","messageTemplate","declarationRequired","expression","required","selectRequired","selectYesNoRequired","max","min","minMax","pattern","format","number","numberPrecision","numberInteger","numberMin","numberMax","maxWords","objectRequired","objectMissing","dateFormat","dateMin","dateMax","messages","messagesPre","validationOptions","abortEarly","errors","wrap","array","label"],"sources":["../../../../../src/server/plugins/engine/pageControllers/validationOptions.ts"],"sourcesContent":["// Declaration above is needed for: https://github.com/hapijs/joi/issues/3064\n\nimport joi, {\n type JoiExpression,\n type LanguageMessages,\n type LanguageMessagesExt,\n type ReferenceOptions,\n type ValidationOptions\n} from 'joi'\n\nimport { lowerFirstPreserveProperNouns } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nconst opts = {\n functions: {\n lowerFirst: lowerFirstPreserveProperNouns\n }\n} as ReferenceOptions\n\n/**\n * see @link https://joi.dev/api/?v=17.4.2#template-syntax for template syntax\n */\nexport const messageTemplate: Record<string, JoiExpression> = {\n declarationRequired: joi.expression(\n 'You must confirm you understand and agree with the {{lowerFirst(#label)}} to continue',\n opts\n ) as JoiExpression,\n required: joi.expression(\n 'Enter {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectRequired: joi.expression(\n 'Select {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectYesNoRequired: '{{#label}} - select yes or no',\n max: '{{#label}} must be {{#limit}} characters or less',\n min: '{{#label}} must be {{#limit}} characters or more',\n minMax: '{{#label}} must be between {{#min}} and {{#max}} characters',\n pattern: joi.expression(\n 'Enter a valid {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n format: joi.expression(\n 'Enter {{lowerFirst(#label)}} in the correct format',\n opts\n ) as JoiExpression,\n number: '{{#label}} must be a number',\n numberPrecision: '{{#label}} must have {{#limit}} or fewer decimal places',\n numberInteger: '{{#label}} must be a whole number',\n numberMin: '{{#label}} must be {{#limit}} or higher',\n numberMax: '{{#label}} must be {{#limit}} or lower',\n maxWords: '{{#label}} must be {{#limit}} words or fewer',\n\n // Nested fields use component title\n\n objectRequired: joi.expression('Enter {{#label}}', opts) as JoiExpression,\n objectMissing: joi.expression(\n '{{#title}} must include a {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n dateFormat: '{{#title}} must be a real date',\n dateMin: '{{#title}} must be the same as or after {{#limit}}',\n dateMax: '{{#title}} must be the same as or before {{#limit}}'\n}\n\nexport const messages: LanguageMessagesExt = {\n 'string.base': messageTemplate.required,\n 'string.min': messageTemplate.min,\n 'string.empty': messageTemplate.required,\n 'string.max': messageTemplate.max,\n 'string.email': messageTemplate.format,\n 'string.pattern.base': messageTemplate.pattern,\n 'string.maxWords': messageTemplate.maxWords,\n\n 'number.base': messageTemplate.number,\n 'number.precision': messageTemplate.numberPrecision,\n 'number.integer': messageTemplate.numberInteger,\n 'number.unsafe': messageTemplate.format,\n 'number.min': messageTemplate.numberMin,\n 'number.max': messageTemplate.numberMax,\n\n 'object.required': messageTemplate.objectRequired,\n 'object.and': messageTemplate.objectMissing,\n\n 'any.only': messageTemplate.selectRequired,\n 'any.required': messageTemplate.selectRequired,\n 'any.empty': messageTemplate.required,\n\n 'date.base': messageTemplate.dateFormat,\n 'date.format': messageTemplate.dateFormat,\n 'date.min': messageTemplate.dateMin,\n 'date.max': messageTemplate.dateMax,\n\n 'object.invalidjson': messageTemplate.format\n}\n\nexport const messagesPre: LanguageMessages =\n messages as unknown as LanguageMessages\n\nexport const validationOptions: ValidationOptions = {\n abortEarly: false,\n messages: messagesPre,\n errors: {\n wrap: {\n array: false,\n label: false\n }\n }\n}\n"],"mappings":"AAAA;;AAEA,OAAOA,GAAG,MAMH,KAAK;AAEZ,SAASC,6BAA6B;AAEtC,MAAMC,IAAI,GAAG;EACXC,SAAS,EAAE;IACTC,UAAU,EAAEH;EACd;AACF,CAAqB;;AAErB;AACA;AACA;AACA,OAAO,MAAMI,eAA8C,GAAG;EAC5DC,mBAAmB,EAAEN,GAAG,CAACO,UAAU,CACjC,uFAAuF,EACvFL,IACF,CAAkB;EAClBM,QAAQ,EAAER,GAAG,CAACO,UAAU,CACtB,8BAA8B,EAC9BL,IACF,CAAkB;EAClBO,cAAc,EAAET,GAAG,CAACO,UAAU,CAC5B,+BAA+B,EAC/BL,IACF,CAAkB;EAClBQ,mBAAmB,EAAE,+BAA+B;EACpDC,GAAG,EAAE,kDAAkD;EACvDC,GAAG,EAAE,kDAAkD;EACvDC,MAAM,EAAE,6DAA6D;EACrEC,OAAO,EAAEd,GAAG,CAACO,UAAU,CACrB,sCAAsC,EACtCL,IACF,CAAkB;EAClBa,MAAM,EAAEf,GAAG,CAACO,UAAU,CACpB,oDAAoD,EACpDL,IACF,CAAkB;EAClBc,MAAM,EAAE,6BAA6B;EACrCC,eAAe,EAAE,yDAAyD;EAC1EC,aAAa,EAAE,mCAAmC;EAClDC,SAAS,EAAE,yCAAyC;EACpDC,SAAS,EAAE,wCAAwC;EACnDC,QAAQ,EAAE,8CAA8C;EAExD;;EAEAC,cAAc,
|
|
1
|
+
{"version":3,"file":"validationOptions.js","names":["joi","lowerFirstPreserveProperNouns","opts","functions","lowerFirst","messageTemplate","declarationRequired","expression","required","selectRequired","selectYesNoRequired","max","min","minMax","pattern","format","unicode","number","numberPrecision","numberInteger","numberMin","numberMax","maxWords","objectRequired","objectMissing","dateFormat","dateMin","dateMax","messages","messagesPre","validationOptions","abortEarly","errors","wrap","array","label"],"sources":["../../../../../src/server/plugins/engine/pageControllers/validationOptions.ts"],"sourcesContent":["// Declaration above is needed for: https://github.com/hapijs/joi/issues/3064\n\nimport joi, {\n type JoiExpression,\n type LanguageMessages,\n type LanguageMessagesExt,\n type ReferenceOptions,\n type ValidationOptions\n} from 'joi'\n\nimport { lowerFirstPreserveProperNouns } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nconst opts = {\n functions: {\n lowerFirst: lowerFirstPreserveProperNouns\n }\n} as ReferenceOptions\n\n/**\n * see @link https://joi.dev/api/?v=17.4.2#template-syntax for template syntax\n */\nexport const messageTemplate: Record<string, JoiExpression> = {\n declarationRequired: joi.expression(\n 'You must confirm you understand and agree with the {{lowerFirst(#label)}} to continue',\n opts\n ) as JoiExpression,\n required: joi.expression(\n 'Enter {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectRequired: joi.expression(\n 'Select {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectYesNoRequired: '{{#label}} - select yes or no',\n max: '{{#label}} must be {{#limit}} characters or less',\n min: '{{#label}} must be {{#limit}} characters or more',\n minMax: '{{#label}} must be between {{#min}} and {{#max}} characters',\n pattern: joi.expression(\n 'Enter a valid {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n format: joi.expression(\n 'Enter {{lowerFirst(#label)}} in the correct format',\n opts\n ) as JoiExpression,\n unicode: '{{#label}} includes invalid characters, for example, long dashes',\n number: '{{#label}} must be a number',\n numberPrecision: '{{#label}} must have {{#limit}} or fewer decimal places',\n numberInteger: '{{#label}} must be a whole number',\n numberMin: '{{#label}} must be {{#limit}} or higher',\n numberMax: '{{#label}} must be {{#limit}} or lower',\n maxWords: '{{#label}} must be {{#limit}} words or fewer',\n\n // Nested fields use component title\n\n objectRequired: joi.expression('Enter {{#label}}', opts) as JoiExpression,\n objectMissing: joi.expression(\n '{{#title}} must include a {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n dateFormat: '{{#title}} must be a real date',\n dateMin: '{{#title}} must be the same as or after {{#limit}}',\n dateMax: '{{#title}} must be the same as or before {{#limit}}'\n}\n\nexport const messages: LanguageMessagesExt = {\n 'string.base': messageTemplate.required,\n 'string.min': messageTemplate.min,\n 'string.empty': messageTemplate.required,\n 'string.max': messageTemplate.max,\n 'string.email': messageTemplate.format,\n 'string.unicode': messageTemplate.unicode,\n 'string.pattern.base': messageTemplate.pattern,\n 'string.maxWords': messageTemplate.maxWords,\n\n 'number.base': messageTemplate.number,\n 'number.precision': messageTemplate.numberPrecision,\n 'number.integer': messageTemplate.numberInteger,\n 'number.unsafe': messageTemplate.format,\n 'number.min': messageTemplate.numberMin,\n 'number.max': messageTemplate.numberMax,\n\n 'object.required': messageTemplate.objectRequired,\n 'object.and': messageTemplate.objectMissing,\n\n 'any.only': messageTemplate.selectRequired,\n 'any.required': messageTemplate.selectRequired,\n 'any.empty': messageTemplate.required,\n\n 'date.base': messageTemplate.dateFormat,\n 'date.format': messageTemplate.dateFormat,\n 'date.min': messageTemplate.dateMin,\n 'date.max': messageTemplate.dateMax,\n\n 'object.invalidjson': messageTemplate.format\n}\n\nexport const messagesPre: LanguageMessages =\n messages as unknown as LanguageMessages\n\nexport const validationOptions: ValidationOptions = {\n abortEarly: false,\n messages: messagesPre,\n errors: {\n wrap: {\n array: false,\n label: false\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|