@defra/forms-engine-plugin 4.0.23 → 4.0.24
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/components/EastingNorthingField.js +7 -6
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
- package/.server/server/plugins/engine/components/LatLongField.js +7 -6
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +4 -4
- package/.server/server/plugins/engine/components/LocationFieldBase.js +3 -2
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +3 -3
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +5 -3
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +3 -3
- package/.server/server/plugins/engine/components/OsGridRefField.js +5 -3
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/index.d.ts +10 -0
- package/.server/server/plugins/engine/components/helpers/index.js +18 -0
- package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
- package/package.json +1 -1
- package/src/server/plugins/engine/components/EastingNorthingField.test.ts +30 -1
- package/src/server/plugins/engine/components/EastingNorthingField.ts +19 -6
- package/src/server/plugins/engine/components/LatLongField.test.ts +30 -1
- package/src/server/plugins/engine/components/LatLongField.ts +19 -6
- package/src/server/plugins/engine/components/LocationFieldBase.ts +11 -6
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +4 -4
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +11 -4
- package/src/server/plugins/engine/components/OsGridRefField.test.ts +4 -4
- package/src/server/plugins/engine/components/OsGridRefField.ts +11 -3
- package/src/server/plugins/engine/components/helpers/helpers.test.ts +40 -0
- package/src/server/plugins/engine/components/helpers/index.ts +18 -0
|
@@ -4,6 +4,7 @@ import { ComponentCollection } from "./ComponentCollection.js";
|
|
|
4
4
|
import { FormComponent, isFormState } from "./FormComponent.js";
|
|
5
5
|
import { deduplicateErrorsByHref, getLocationFieldViewModel } from "./LocationFieldHelpers.js";
|
|
6
6
|
import { NumberField } from "./NumberField.js";
|
|
7
|
+
import { createLowerFirstExpression } from "./helpers/index.js";
|
|
7
8
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
8
9
|
import { convertToLanguageMessages } from "../../../utils/type-utils.js";
|
|
9
10
|
|
|
@@ -142,23 +143,23 @@ export class EastingNorthingField extends FormComponent {
|
|
|
142
143
|
template: messageTemplate.required
|
|
143
144
|
}, {
|
|
144
145
|
type: 'eastingFormat',
|
|
145
|
-
template: 'Easting for {{#title}} must be between 1 and 6 digits'
|
|
146
|
+
template: createLowerFirstExpression('Easting for {{lowerFirst(#title)}} must be between 1 and 6 digits')
|
|
146
147
|
}, {
|
|
147
148
|
type: 'northingFormat',
|
|
148
|
-
template: 'Northing for {{#title}} must be between 1 and 7 digits'
|
|
149
|
+
template: createLowerFirstExpression('Northing for {{lowerFirst(#title)}} must be between 1 and 7 digits')
|
|
149
150
|
}],
|
|
150
151
|
advancedSettingsErrors: [{
|
|
151
152
|
type: 'eastingMin',
|
|
152
|
-
template: `Easting for {{#title}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`
|
|
153
|
+
template: createLowerFirstExpression(`Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`)
|
|
153
154
|
}, {
|
|
154
155
|
type: 'eastingMax',
|
|
155
|
-
template: `Easting for {{#title}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`
|
|
156
|
+
template: createLowerFirstExpression(`Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`)
|
|
156
157
|
}, {
|
|
157
158
|
type: 'northingMin',
|
|
158
|
-
template: `Northing for {{#title}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`
|
|
159
|
+
template: createLowerFirstExpression(`Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`)
|
|
159
160
|
}, {
|
|
160
161
|
type: 'northingMax',
|
|
161
|
-
template: `Northing for {{#title}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`
|
|
162
|
+
template: createLowerFirstExpression(`Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`)
|
|
162
163
|
}]
|
|
163
164
|
};
|
|
164
165
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EastingNorthingField.js","names":["ComponentType","lowerFirst","ComponentCollection","FormComponent","isFormState","deduplicateErrorsByHref","getLocationFieldViewModel","NumberField","messageTemplate","convertToLanguageMessages","DEFAULT_EASTING_MIN","DEFAULT_EASTING_MAX","DEFAULT_NORTHING_MIN","DEFAULT_NORTHING_MAX","EastingNorthingField","constructor","def","props","name","options","schema","isRequired","required","eastingMin","easting","min","eastingMax","max","northingMin","northing","northingMax","eastingRequired","northingRequired","eastingDigitsMessage","label","northingDigitsMessage","customValidationMessages","northingValidationMessages","collection","type","title","precision","optionalText","classes","parent","peers","formSchema","stateSchema","getFormValueFromState","state","value","isEastingNorthing","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","getViewErrors","allErrors","getErrors","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber"],"sources":["../../../../../src/server/plugins/engine/components/EastingNorthingField.ts"],"sourcesContent":["import {\n ComponentType,\n type EastingNorthingFieldComponent\n} from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n deduplicateErrorsByHref,\n getLocationFieldViewModel\n} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { type EastingNorthingState } from '~/src/server/plugins/engine/components/types.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} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\n// British National Grid coordinate limits\nconst DEFAULT_EASTING_MIN = 0\nconst DEFAULT_EASTING_MAX = 700000\nconst DEFAULT_NORTHING_MIN = 0\nconst DEFAULT_NORTHING_MAX = 1300000\n\nexport class EastingNorthingField extends FormComponent {\n declare options: EastingNorthingFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: EastingNorthingFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options, schema } = def\n\n const isRequired = options.required !== false\n\n const eastingMin = schema?.easting?.min ?? DEFAULT_EASTING_MIN\n const eastingMax = schema?.easting?.max ?? DEFAULT_EASTING_MAX\n const northingMin = schema?.northing?.min ?? DEFAULT_NORTHING_MIN\n const northingMax = schema?.northing?.max ?? DEFAULT_NORTHING_MAX\n\n const eastingRequired = 'Enter easting'\n const northingRequired = 'Enter northing'\n\n const eastingDigitsMessage = `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 6 digits`\n const northingDigitsMessage = `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 7 digits`\n\n const customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': eastingRequired,\n 'number.base': eastingRequired,\n 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${eastingMax}`,\n 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${eastingMin} and {{#limit}}`,\n 'number.precision': eastingDigitsMessage,\n 'number.integer': eastingDigitsMessage,\n 'number.unsafe': eastingDigitsMessage\n })\n\n const northingValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': northingRequired,\n 'number.base': northingRequired,\n 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${northingMax}`,\n 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${northingMin} and {{#limit}}`,\n 'number.precision': northingDigitsMessage,\n 'number.integer': northingDigitsMessage,\n 'number.unsafe': northingDigitsMessage\n })\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__easting`,\n title: 'Easting',\n schema: {\n min: eastingMin,\n max: eastingMax,\n precision: 0\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__northing`,\n title: 'Northing',\n schema: {\n min: northingMin,\n max: northingMax,\n precision: 0\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n customValidationMessages: northingValidationMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n peers: [`${name}__easting`, `${name}__northing`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return EastingNorthingField.isEastingNorthing(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(\n value: EastingNorthingState | undefined\n ): string {\n if (!value) {\n return ''\n }\n\n // CYA page format: <<eastingvalue, northingvalue>>\n return `${value.easting}, ${value.northing}`\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: EastingNorthingState | undefined\n ): string | null {\n if (!value) {\n return null\n }\n\n return `Easting: ${value.easting}\\nNorthing: ${value.northing}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n return getLocationFieldViewModel(this, viewModel, payload, errors)\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const allErrors = this.getErrors(errors)\n return deduplicateErrorsByHref(allErrors)\n }\n\n isState(value?: FormStateValue | FormState) {\n return EastingNorthingField.isEastingNorthing(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return EastingNorthingField.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 {\n type: 'eastingFormat',\n template: 'Easting for {{#title}} must be between 1 and 6 digits'\n },\n {\n type: 'northingFormat',\n template: 'Northing for {{#title}} must be between 1 and 7 digits'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'eastingMin',\n template: `Easting for {{#title}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`\n },\n {\n type: 'eastingMax',\n template: `Easting for {{#title}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`\n },\n {\n type: 'northingMin',\n template: `Northing for {{#title}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n },\n {\n type: 'northingMax',\n template: `Northing for {{#title}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n }\n ]\n }\n }\n\n static isEastingNorthing(\n value?: FormStateValue | FormState\n ): value is EastingNorthingState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.easting) &&\n NumberField.isNumber(value.northing)\n )\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"EastingNorthingField.js","names":["ComponentType","lowerFirst","ComponentCollection","FormComponent","isFormState","deduplicateErrorsByHref","getLocationFieldViewModel","NumberField","createLowerFirstExpression","messageTemplate","convertToLanguageMessages","DEFAULT_EASTING_MIN","DEFAULT_EASTING_MAX","DEFAULT_NORTHING_MIN","DEFAULT_NORTHING_MAX","EastingNorthingField","constructor","def","props","name","options","schema","isRequired","required","eastingMin","easting","min","eastingMax","max","northingMin","northing","northingMax","eastingRequired","northingRequired","eastingDigitsMessage","label","northingDigitsMessage","customValidationMessages","northingValidationMessages","collection","type","title","precision","optionalText","classes","parent","peers","formSchema","stateSchema","getFormValueFromState","state","value","isEastingNorthing","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","getViewErrors","allErrors","getErrors","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber"],"sources":["../../../../../src/server/plugins/engine/components/EastingNorthingField.ts"],"sourcesContent":["import {\n ComponentType,\n type EastingNorthingFieldComponent\n} from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n deduplicateErrorsByHref,\n getLocationFieldViewModel\n} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { type EastingNorthingState } from '~/src/server/plugins/engine/components/types.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} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\n// British National Grid coordinate limits\nconst DEFAULT_EASTING_MIN = 0\nconst DEFAULT_EASTING_MAX = 700000\nconst DEFAULT_NORTHING_MIN = 0\nconst DEFAULT_NORTHING_MAX = 1300000\n\nexport class EastingNorthingField extends FormComponent {\n declare options: EastingNorthingFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: EastingNorthingFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options, schema } = def\n\n const isRequired = options.required !== false\n\n const eastingMin = schema?.easting?.min ?? DEFAULT_EASTING_MIN\n const eastingMax = schema?.easting?.max ?? DEFAULT_EASTING_MAX\n const northingMin = schema?.northing?.min ?? DEFAULT_NORTHING_MIN\n const northingMax = schema?.northing?.max ?? DEFAULT_NORTHING_MAX\n\n const eastingRequired = 'Enter easting'\n const northingRequired = 'Enter northing'\n\n const eastingDigitsMessage = `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 6 digits`\n const northingDigitsMessage = `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 7 digits`\n\n const customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': eastingRequired,\n 'number.base': eastingRequired,\n 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${eastingMax}`,\n 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${eastingMin} and {{#limit}}`,\n 'number.precision': eastingDigitsMessage,\n 'number.integer': eastingDigitsMessage,\n 'number.unsafe': eastingDigitsMessage\n })\n\n const northingValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': northingRequired,\n 'number.base': northingRequired,\n 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${northingMax}`,\n 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${northingMin} and {{#limit}}`,\n 'number.precision': northingDigitsMessage,\n 'number.integer': northingDigitsMessage,\n 'number.unsafe': northingDigitsMessage\n })\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__easting`,\n title: 'Easting',\n schema: {\n min: eastingMin,\n max: eastingMax,\n precision: 0\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n customValidationMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__northing`,\n title: 'Northing',\n schema: {\n min: northingMin,\n max: northingMax,\n precision: 0\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n customValidationMessages: northingValidationMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n peers: [`${name}__easting`, `${name}__northing`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return EastingNorthingField.isEastingNorthing(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(\n value: EastingNorthingState | undefined\n ): string {\n if (!value) {\n return ''\n }\n\n // CYA page format: <<eastingvalue, northingvalue>>\n return `${value.easting}, ${value.northing}`\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: EastingNorthingState | undefined\n ): string | null {\n if (!value) {\n return null\n }\n\n return `Easting: ${value.easting}\\nNorthing: ${value.northing}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n return getLocationFieldViewModel(this, viewModel, payload, errors)\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const allErrors = this.getErrors(errors)\n return deduplicateErrorsByHref(allErrors)\n }\n\n isState(value?: FormStateValue | FormState) {\n return EastingNorthingField.isEastingNorthing(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return EastingNorthingField.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 {\n type: 'eastingFormat',\n template: createLowerFirstExpression(\n 'Easting for {{lowerFirst(#title)}} must be between 1 and 6 digits'\n )\n },\n {\n type: 'northingFormat',\n template: createLowerFirstExpression(\n 'Northing for {{lowerFirst(#title)}} must be between 1 and 7 digits'\n )\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'eastingMin',\n template: createLowerFirstExpression(\n `Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`\n )\n },\n {\n type: 'eastingMax',\n template: createLowerFirstExpression(\n `Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`\n )\n },\n {\n type: 'northingMin',\n template: createLowerFirstExpression(\n `Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n )\n },\n {\n type: 'northingMax',\n template: createLowerFirstExpression(\n `Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n )\n }\n ]\n }\n }\n\n static isEastingNorthing(\n value?: FormStateValue | FormState\n ): value is EastingNorthingState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.easting) &&\n NumberField.isNumber(value.northing)\n )\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ import { ComponentCollection } from "./ComponentCollection.js";
|
|
|
4
4
|
import { FormComponent, isFormState } from "./FormComponent.js";
|
|
5
5
|
import { deduplicateErrorsByHref, getLocationFieldViewModel } from "./LocationFieldHelpers.js";
|
|
6
6
|
import { NumberField } from "./NumberField.js";
|
|
7
|
+
import { createLowerFirstExpression } from "./helpers/index.js";
|
|
7
8
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
8
9
|
import { convertToLanguageMessages } from "../../../utils/type-utils.js";
|
|
9
10
|
|
|
@@ -147,23 +148,23 @@ export class LatLongField extends FormComponent {
|
|
|
147
148
|
template: messageTemplate.required
|
|
148
149
|
}, {
|
|
149
150
|
type: 'latitudeFormat',
|
|
150
|
-
template: 'Enter a valid latitude for {{#title}} like 51.519450'
|
|
151
|
+
template: createLowerFirstExpression('Enter a valid latitude for {{lowerFirst(#title)}} like 51.519450')
|
|
151
152
|
}, {
|
|
152
153
|
type: 'longitudeFormat',
|
|
153
|
-
template: 'Enter a valid longitude for {{#title}} like -0.127758'
|
|
154
|
+
template: createLowerFirstExpression('Enter a valid longitude for {{lowerFirst(#title)}} like -0.127758')
|
|
154
155
|
}],
|
|
155
156
|
advancedSettingsErrors: [{
|
|
156
157
|
type: 'latitudeMin',
|
|
157
|
-
template: 'Latitude for {{#title}} must be between 49 and 60'
|
|
158
|
+
template: createLowerFirstExpression('Latitude for {{lowerFirst(#title)}} must be between 49 and 60')
|
|
158
159
|
}, {
|
|
159
160
|
type: 'latitudeMax',
|
|
160
|
-
template: 'Latitude for {{#title}} must be between 49 and 60'
|
|
161
|
+
template: createLowerFirstExpression('Latitude for {{lowerFirst(#title)}} must be between 49 and 60')
|
|
161
162
|
}, {
|
|
162
163
|
type: 'longitudeMin',
|
|
163
|
-
template: 'Longitude for {{#title}} must be between -9 and 2'
|
|
164
|
+
template: createLowerFirstExpression('Longitude for {{lowerFirst(#title)}} must be between -9 and 2')
|
|
164
165
|
}, {
|
|
165
166
|
type: 'longitudeMax',
|
|
166
|
-
template: 'Longitude for {{#title}} must be between -9 and 2'
|
|
167
|
+
template: createLowerFirstExpression('Longitude for {{lowerFirst(#title)}} must be between -9 and 2')
|
|
167
168
|
}]
|
|
168
169
|
};
|
|
169
170
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LatLongField.js","names":["ComponentType","lowerFirst","ComponentCollection","FormComponent","isFormState","deduplicateErrorsByHref","getLocationFieldViewModel","NumberField","messageTemplate","convertToLanguageMessages","DECIMAL_PRECISION","LatLongField","constructor","def","props","name","options","schema","isRequired","required","latitudeMin","latitude","min","latitudeMax","max","longitudeMin","longitude","longitudeMax","latitudeRequired","longitudeRequired","customValidationMessages","latitudeRangeMessage","label","longitudeRangeMessage","latitudeMessages","longitudeMessages","collection","type","title","precision","optionalText","classes","suffix","parent","peers","formSchema","stateSchema","getFormValueFromState","state","value","isLatLong","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","getViewErrors","allErrors","getErrors","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber"],"sources":["../../../../../src/server/plugins/engine/components/LatLongField.ts"],"sourcesContent":["import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n deduplicateErrorsByHref,\n getLocationFieldViewModel\n} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { type LatLongState } from '~/src/server/plugins/engine/components/types.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} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\n// Precision constants\n// UK latitude/longitude requires high precision for accurate location (within ~11mm)\nconst DECIMAL_PRECISION = 7 // 7 decimal places\n\nexport class LatLongField extends FormComponent {\n declare options: LatLongFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: LatLongFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options, schema } = def\n\n const isRequired = options.required !== false\n\n // Read schema values from def.schema with fallback defaults\n const latitudeMin = schema?.latitude?.min ?? 49.85\n const latitudeMax = schema?.latitude?.max ?? 60.859\n const longitudeMin = schema?.longitude?.min ?? -13.687\n const longitudeMax = schema?.longitude?.max ?? 1.767\n\n const latitudeRequired = 'Enter latitude'\n const longitudeRequired = 'Enter longitude'\n\n const customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'number.precision':\n '{{#label}} must have no more than 7 decimal places',\n 'number.unsafe': '{{#label}} must be a valid number'\n })\n\n const latitudeRangeMessage = `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}`\n const longitudeRangeMessage = `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}`\n\n const latitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'any.required': latitudeRequired,\n 'number.base': `Enter a valid latitude for ${lowerFirst(this.label)} like 51.519450`,\n 'number.min': latitudeRangeMessage,\n 'number.max': latitudeRangeMessage\n })\n\n const longitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'any.required': longitudeRequired,\n 'number.base': `Enter a valid longitude for ${lowerFirst(this.label)} like -0.127758`,\n 'number.min': longitudeRangeMessage,\n 'number.max': longitudeRangeMessage\n })\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__latitude`,\n title: 'Latitude',\n schema: {\n min: latitudeMin,\n max: latitudeMax,\n precision: DECIMAL_PRECISION\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n suffix: '°',\n customValidationMessages: latitudeMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__longitude`,\n title: 'Longitude',\n schema: {\n min: longitudeMin,\n max: longitudeMax,\n precision: DECIMAL_PRECISION\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n suffix: '°',\n customValidationMessages: longitudeMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n peers: [`${name}__latitude`, `${name}__longitude`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return LatLongField.isLatLong(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: LatLongState | undefined): string {\n if (!value) {\n return ''\n }\n\n // CYA page format: <<latvalue, langvalue>>\n return `${value.latitude}, ${value.longitude}`\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(value: LatLongState | undefined): string | null {\n if (!value) {\n return null\n }\n\n // Output format: Latitude: <<entry>>\\nLongitude: <<entry>>\n return `Latitude: ${value.latitude}\\nLongitude: ${value.longitude}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n return getLocationFieldViewModel(this, viewModel, payload, errors)\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const allErrors = this.getErrors(errors)\n return deduplicateErrorsByHref(allErrors)\n }\n\n isState(value?: FormStateValue | FormState) {\n return LatLongField.isLatLong(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return LatLongField.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 {\n type: 'latitudeFormat',\n template: 'Enter a valid latitude for {{#title}} like 51.519450'\n },\n {\n type: 'longitudeFormat',\n template: 'Enter a valid longitude for {{#title}} like -0.127758'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'latitudeMin',\n template: 'Latitude for {{#title}} must be between 49 and 60'\n },\n {\n type: 'latitudeMax',\n template: 'Latitude for {{#title}} must be between 49 and 60'\n },\n {\n type: 'longitudeMin',\n template: 'Longitude for {{#title}} must be between -9 and 2'\n },\n {\n type: 'longitudeMax',\n template: 'Longitude for {{#title}} must be between -9 and 2'\n }\n ]\n }\n }\n\n static isLatLong(value?: FormStateValue | FormState): value is LatLongState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.latitude) &&\n NumberField.isNumber(value.longitude)\n )\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"LatLongField.js","names":["ComponentType","lowerFirst","ComponentCollection","FormComponent","isFormState","deduplicateErrorsByHref","getLocationFieldViewModel","NumberField","createLowerFirstExpression","messageTemplate","convertToLanguageMessages","DECIMAL_PRECISION","LatLongField","constructor","def","props","name","options","schema","isRequired","required","latitudeMin","latitude","min","latitudeMax","max","longitudeMin","longitude","longitudeMax","latitudeRequired","longitudeRequired","customValidationMessages","latitudeRangeMessage","label","longitudeRangeMessage","latitudeMessages","longitudeMessages","collection","type","title","precision","optionalText","classes","suffix","parent","peers","formSchema","stateSchema","getFormValueFromState","state","value","isLatLong","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","getViewErrors","allErrors","getErrors","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber"],"sources":["../../../../../src/server/plugins/engine/components/LatLongField.ts"],"sourcesContent":["import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n deduplicateErrorsByHref,\n getLocationFieldViewModel\n} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'\nimport { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { type LatLongState } from '~/src/server/plugins/engine/components/types.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} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\n// Precision constants\n// UK latitude/longitude requires high precision for accurate location (within ~11mm)\nconst DECIMAL_PRECISION = 7 // 7 decimal places\n\nexport class LatLongField extends FormComponent {\n declare options: LatLongFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: LatLongFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options, schema } = def\n\n const isRequired = options.required !== false\n\n // Read schema values from def.schema with fallback defaults\n const latitudeMin = schema?.latitude?.min ?? 49.85\n const latitudeMax = schema?.latitude?.max ?? 60.859\n const longitudeMin = schema?.longitude?.min ?? -13.687\n const longitudeMax = schema?.longitude?.max ?? 1.767\n\n const latitudeRequired = 'Enter latitude'\n const longitudeRequired = 'Enter longitude'\n\n const customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'number.precision':\n '{{#label}} must have no more than 7 decimal places',\n 'number.unsafe': '{{#label}} must be a valid number'\n })\n\n const latitudeRangeMessage = `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}`\n const longitudeRangeMessage = `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}`\n\n const latitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'any.required': latitudeRequired,\n 'number.base': `Enter a valid latitude for ${lowerFirst(this.label)} like 51.519450`,\n 'number.min': latitudeRangeMessage,\n 'number.max': latitudeRangeMessage\n })\n\n const longitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'any.required': longitudeRequired,\n 'number.base': `Enter a valid longitude for ${lowerFirst(this.label)} like -0.127758`,\n 'number.min': longitudeRangeMessage,\n 'number.max': longitudeRangeMessage\n })\n\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.NumberField,\n name: `${name}__latitude`,\n title: 'Latitude',\n schema: {\n min: latitudeMin,\n max: latitudeMax,\n precision: DECIMAL_PRECISION\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n suffix: '°',\n customValidationMessages: latitudeMessages\n }\n },\n {\n type: ComponentType.NumberField,\n name: `${name}__longitude`,\n title: 'Longitude',\n schema: {\n min: longitudeMin,\n max: longitudeMax,\n precision: DECIMAL_PRECISION\n },\n options: {\n required: isRequired,\n optionalText: true,\n classes: 'govuk-input--width-10',\n suffix: '°',\n customValidationMessages: longitudeMessages\n }\n }\n ],\n { ...props, parent: this },\n {\n peers: [`${name}__latitude`, `${name}__longitude`]\n }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return LatLongField.isLatLong(value) ? value : undefined\n }\n\n getDisplayStringFromFormValue(value: LatLongState | undefined): string {\n if (!value) {\n return ''\n }\n\n // CYA page format: <<latvalue, langvalue>>\n return `${value.latitude}, ${value.longitude}`\n }\n\n getDisplayStringFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(value: LatLongState | undefined): string | null {\n if (!value) {\n return null\n }\n\n // Output format: Latitude: <<entry>>\\nLongitude: <<entry>>\n return `Latitude: ${value.latitude}\\nLongitude: ${value.longitude}`\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n return getLocationFieldViewModel(this, viewModel, payload, errors)\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const allErrors = this.getErrors(errors)\n return deduplicateErrorsByHref(allErrors)\n }\n\n isState(value?: FormStateValue | FormState) {\n return LatLongField.isLatLong(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return LatLongField.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 {\n type: 'latitudeFormat',\n template: createLowerFirstExpression(\n 'Enter a valid latitude for {{lowerFirst(#title)}} like 51.519450'\n )\n },\n {\n type: 'longitudeFormat',\n template: createLowerFirstExpression(\n 'Enter a valid longitude for {{lowerFirst(#title)}} like -0.127758'\n )\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'latitudeMin',\n template: createLowerFirstExpression(\n 'Latitude for {{lowerFirst(#title)}} must be between 49 and 60'\n )\n },\n {\n type: 'latitudeMax',\n template: createLowerFirstExpression(\n 'Latitude for {{lowerFirst(#title)}} must be between 49 and 60'\n )\n },\n {\n type: 'longitudeMin',\n template: createLowerFirstExpression(\n 'Longitude for {{lowerFirst(#title)}} must be between -9 and 2'\n )\n },\n {\n type: 'longitudeMax',\n template: createLowerFirstExpression(\n 'Longitude for {{lowerFirst(#title)}} must be between -9 and 2'\n )\n }\n ]\n }\n }\n\n static isLatLong(value?: FormStateValue | FormState): value is LatLongState {\n return (\n isFormState(value) &&\n NumberField.isNumber(value.latitude) &&\n NumberField.isNumber(value.longitude)\n )\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FormComponentsDef } from '@defra/forms-model';
|
|
2
|
-
import { type LanguageMessages, type StringSchema } from 'joi';
|
|
2
|
+
import { type JoiExpression, type LanguageMessages, type StringSchema } from 'joi';
|
|
3
3
|
import { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js';
|
|
4
4
|
import { type ErrorMessageTemplateList, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState } from '~/src/server/plugins/engine/types.js';
|
|
5
5
|
interface LocationFieldOptions {
|
|
@@ -11,8 +11,8 @@ interface LocationFieldOptions {
|
|
|
11
11
|
}
|
|
12
12
|
interface ValidationConfig {
|
|
13
13
|
pattern: RegExp;
|
|
14
|
-
patternErrorMessage:
|
|
15
|
-
requiredMessage?:
|
|
14
|
+
patternErrorMessage: JoiExpression;
|
|
15
|
+
requiredMessage?: JoiExpression;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Abstract base class for location-based field components
|
|
@@ -25,7 +25,7 @@ export declare abstract class LocationFieldBase extends FormComponent {
|
|
|
25
25
|
protected abstract getValidationConfig(): ValidationConfig;
|
|
26
26
|
protected abstract getErrorTemplates(): {
|
|
27
27
|
type: string;
|
|
28
|
-
template:
|
|
28
|
+
template: JoiExpression;
|
|
29
29
|
}[];
|
|
30
30
|
constructor(def: FormComponentsDef, props: ConstructorParameters<typeof FormComponent>[1]);
|
|
31
31
|
getFormValueFromState(state: FormSubmissionState): string | undefined;
|
|
@@ -2,6 +2,7 @@ import joi from 'joi';
|
|
|
2
2
|
import { FormComponent, isFormValue } from "./FormComponent.js";
|
|
3
3
|
import { addClassOptionIfNone } from "./helpers/index.js";
|
|
4
4
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
5
|
+
import { convertToLanguageMessages } from "../../../utils/type-utils.js";
|
|
5
6
|
/**
|
|
6
7
|
* Abstract base class for location-based field components
|
|
7
8
|
*/
|
|
@@ -17,11 +18,11 @@ export class LocationFieldBase extends FormComponent {
|
|
|
17
18
|
addClassOptionIfNone(locationOptions, 'govuk-input--width-10');
|
|
18
19
|
const config = this.getValidationConfig();
|
|
19
20
|
const requiredMessage = config.requiredMessage ?? messageTemplate.required;
|
|
20
|
-
const messages = {
|
|
21
|
+
const messages = convertToLanguageMessages({
|
|
21
22
|
'any.required': requiredMessage,
|
|
22
23
|
'string.empty': requiredMessage,
|
|
23
24
|
'string.pattern.base': config.patternErrorMessage
|
|
24
|
-
};
|
|
25
|
+
});
|
|
25
26
|
let formSchema = joi.string().trim().label(this.label).required().pattern(config.pattern).messages(messages);
|
|
26
27
|
if (locationOptions.required === false) {
|
|
27
28
|
formSchema = formSchema.allow('');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocationFieldBase.js","names":["joi","FormComponent","isFormValue","addClassOptionIfNone","messageTemplate","LocationFieldBase","instructionText","constructor","def","props","options","locationOptions","config","getValidationConfig","requiredMessage","required","messages","patternErrorMessage","formSchema","string","trim","label","pattern","allow","customValidationMessage","message","messageKeys","reduce","acc","key","customValidationMessages","default","stateSchema","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","isText","getViewModel","payload","errors","viewModel","getAllPossibleErrors","baseErrors","type","template","getErrorTemplates","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/LocationFieldBase.ts"],"sourcesContent":["import { type FormComponentsDef } from '@defra/forms-model'\nimport joi, { type LanguageMessages
|
|
1
|
+
{"version":3,"file":"LocationFieldBase.js","names":["joi","FormComponent","isFormValue","addClassOptionIfNone","messageTemplate","convertToLanguageMessages","LocationFieldBase","instructionText","constructor","def","props","options","locationOptions","config","getValidationConfig","requiredMessage","required","messages","patternErrorMessage","formSchema","string","trim","label","pattern","allow","customValidationMessage","message","messageKeys","reduce","acc","key","customValidationMessages","default","stateSchema","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","isText","getViewModel","payload","errors","viewModel","getAllPossibleErrors","baseErrors","type","template","getErrorTemplates","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/LocationFieldBase.ts"],"sourcesContent":["import { type FormComponentsDef } from '@defra/forms-model'\nimport joi, {\n type JoiExpression,\n type LanguageMessages,\n type StringSchema\n} from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { addClassOptionIfNone } from '~/src/server/plugins/engine/components/helpers/index.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} from '~/src/server/plugins/engine/types.js'\nimport { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'\n\ninterface LocationFieldOptions {\n instructionText?: string\n required?: boolean\n customValidationMessage?: string\n customValidationMessages?: LanguageMessages\n classes?: string\n}\n\ninterface ValidationConfig {\n pattern: RegExp\n patternErrorMessage: JoiExpression\n requiredMessage?: JoiExpression\n}\n\n/**\n * Abstract base class for location-based field components\n */\nexport abstract class LocationFieldBase extends FormComponent {\n declare options: LocationFieldOptions\n declare formSchema: StringSchema\n declare stateSchema: StringSchema\n instructionText?: string\n\n protected abstract getValidationConfig(): ValidationConfig\n protected abstract getErrorTemplates(): {\n type: string\n template: JoiExpression\n }[]\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options } = def\n const locationOptions = options as LocationFieldOptions\n this.instructionText = locationOptions.instructionText\n\n addClassOptionIfNone(locationOptions, 'govuk-input--width-10')\n\n const config = this.getValidationConfig()\n const requiredMessage =\n config.requiredMessage ?? (messageTemplate.required as string)\n\n const messages = convertToLanguageMessages({\n 'any.required': requiredMessage,\n 'string.empty': requiredMessage,\n 'string.pattern.base': config.patternErrorMessage\n })\n\n let formSchema = joi\n .string()\n .trim()\n .label(this.label)\n .required()\n .pattern(config.pattern)\n .messages(messages)\n\n if (locationOptions.required === false) {\n formSchema = formSchema.allow('')\n }\n\n if (locationOptions.customValidationMessage) {\n const message = locationOptions.customValidationMessage\n const messageKeys = [\n 'any.required',\n 'string.empty',\n 'string.pattern.base'\n ]\n\n const messages = messageKeys.reduce<LanguageMessages>((acc, key) => {\n acc[key] = message\n return acc\n }, {})\n\n formSchema = formSchema.messages(messages)\n } else if (locationOptions.customValidationMessages) {\n formSchema = formSchema.messages(locationOptions.customValidationMessages)\n }\n\n this.formSchema = formSchema.default('')\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = locationOptions\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n isValue(value?: FormStateValue | FormState): value is string {\n return LocationFieldBase.isText(value)\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n\n if (this.instructionText) {\n return {\n ...viewModel,\n instructionText: this.instructionText\n }\n }\n\n return viewModel\n }\n\n getAllPossibleErrors(): ErrorMessageTemplateList {\n const config = this.getValidationConfig()\n\n return {\n baseErrors: [\n {\n type: 'required',\n template:\n config.requiredMessage ?? (messageTemplate.required as string)\n },\n ...this.getErrorTemplates()\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isText(value?: FormStateValue | FormState): value is string {\n return isFormValue(value) && typeof value === 'string'\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,12 +4,12 @@ export declare class NationalGridFieldNumberField extends LocationFieldBase {
|
|
|
4
4
|
options: NationalGridFieldNumberFieldComponent['options'];
|
|
5
5
|
protected getValidationConfig(): {
|
|
6
6
|
pattern: RegExp;
|
|
7
|
-
patternErrorMessage:
|
|
8
|
-
requiredMessage:
|
|
7
|
+
patternErrorMessage: import("joi").JoiExpression;
|
|
8
|
+
requiredMessage: import("joi").JoiExpression;
|
|
9
9
|
};
|
|
10
10
|
protected getErrorTemplates(): {
|
|
11
11
|
type: string;
|
|
12
|
-
template:
|
|
12
|
+
template: import("joi").JoiExpression;
|
|
13
13
|
}[];
|
|
14
14
|
/**
|
|
15
15
|
* Static version of getAllPossibleErrors that doesn't require a component instance.
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { LocationFieldBase } from "./LocationFieldBase.js";
|
|
2
|
+
import { createLowerFirstExpression } from "./helpers/index.js";
|
|
2
3
|
export class NationalGridFieldNumberField extends LocationFieldBase {
|
|
3
4
|
getValidationConfig() {
|
|
4
5
|
// Regex for OS national grid field references (NGFR)
|
|
5
6
|
// Validates specific valid OS grid letter combinations with:
|
|
6
7
|
// - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789
|
|
7
8
|
const pattern = /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?([0-9]{4})\s?([0-9]{4})$/;
|
|
9
|
+
const patternTemplate = 'Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678';
|
|
8
10
|
return {
|
|
9
11
|
pattern,
|
|
10
|
-
patternErrorMessage:
|
|
11
|
-
requiredMessage: 'Enter {{#title}}'
|
|
12
|
+
patternErrorMessage: createLowerFirstExpression(patternTemplate),
|
|
13
|
+
requiredMessage: createLowerFirstExpression('Enter {{lowerFirst(#title)}}')
|
|
12
14
|
};
|
|
13
15
|
}
|
|
14
16
|
getErrorTemplates() {
|
|
15
17
|
return [{
|
|
16
18
|
type: 'pattern',
|
|
17
|
-
template: 'Enter a valid National Grid field number for {{#title}} like NG 1234 5678'
|
|
19
|
+
template: createLowerFirstExpression('Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678')
|
|
18
20
|
}];
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NationalGridFieldNumberField.js","names":["LocationFieldBase","NationalGridFieldNumberField","getValidationConfig","pattern","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","instance","Object","create","prototype"],"sources":["../../../../../src/server/plugins/engine/components/NationalGridFieldNumberField.ts"],"sourcesContent":["import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model'\n\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\n\nexport class NationalGridFieldNumberField extends LocationFieldBase {\n declare options: NationalGridFieldNumberFieldComponent['options']\n\n protected getValidationConfig() {\n // Regex for OS national grid field references (NGFR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?([0-9]{4})\\s?([0-9]{4})$/\n\n
|
|
1
|
+
{"version":3,"file":"NationalGridFieldNumberField.js","names":["LocationFieldBase","createLowerFirstExpression","NationalGridFieldNumberField","getValidationConfig","pattern","patternTemplate","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","instance","Object","create","prototype"],"sources":["../../../../../src/server/plugins/engine/components/NationalGridFieldNumberField.ts"],"sourcesContent":["import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model'\n\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nexport class NationalGridFieldNumberField extends LocationFieldBase {\n declare options: NationalGridFieldNumberFieldComponent['options']\n\n protected getValidationConfig() {\n // Regex for OS national grid field references (NGFR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?([0-9]{4})\\s?([0-9]{4})$/\n\n const patternTemplate =\n 'Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678'\n\n return {\n pattern,\n patternErrorMessage: createLowerFirstExpression(patternTemplate),\n requiredMessage: createLowerFirstExpression(\n 'Enter {{lowerFirst(#title)}}'\n )\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n 'Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678'\n )\n }\n ]\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors() {\n const instance = Object.create(\n NationalGridFieldNumberField.prototype\n ) as NationalGridFieldNumberField\n return instance.getAllPossibleErrors()\n }\n}\n"],"mappings":"AAEA,SAASA,iBAAiB;AAC1B,SAASC,0BAA0B;AAEnC,OAAO,MAAMC,4BAA4B,SAASF,iBAAiB,CAAC;EAGxDG,mBAAmBA,CAAA,EAAG;IAC9B;IACA;IACA;IACA,MAAMC,OAAO,GACX,mIAAmI;IAErI,MAAMC,eAAe,GACnB,uFAAuF;IAEzF,OAAO;MACLD,OAAO;MACPE,mBAAmB,EAAEL,0BAA0B,CAACI,eAAe,CAAC;MAChEE,eAAe,EAAEN,0BAA0B,CACzC,8BACF;IACF,CAAC;EACH;EAEUO,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EAAET,0BAA0B,CAClC,uFACF;IACF,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOU,oBAAoBA,CAAA,EAAG;IAC5B,MAAMC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAC5BZ,4BAA4B,CAACa,SAC/B,CAAiC;IACjC,OAAOH,QAAQ,CAACD,oBAAoB,CAAC,CAAC;EACxC;AACF","ignoreList":[]}
|
|
@@ -4,12 +4,12 @@ export declare class OsGridRefField extends LocationFieldBase {
|
|
|
4
4
|
options: OsGridRefFieldComponent['options'];
|
|
5
5
|
protected getValidationConfig(): {
|
|
6
6
|
pattern: RegExp;
|
|
7
|
-
patternErrorMessage:
|
|
8
|
-
requiredMessage:
|
|
7
|
+
patternErrorMessage: import("joi").JoiExpression;
|
|
8
|
+
requiredMessage: import("joi").JoiExpression;
|
|
9
9
|
};
|
|
10
10
|
protected getErrorTemplates(): {
|
|
11
11
|
type: string;
|
|
12
|
-
template:
|
|
12
|
+
template: import("joi").JoiExpression;
|
|
13
13
|
}[];
|
|
14
14
|
/**
|
|
15
15
|
* Static version of getAllPossibleErrors that doesn't require a component instance.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LocationFieldBase } from "./LocationFieldBase.js";
|
|
2
|
+
import { createLowerFirstExpression } from "./helpers/index.js";
|
|
2
3
|
export class OsGridRefField extends LocationFieldBase {
|
|
3
4
|
getValidationConfig() {
|
|
4
5
|
// Regex for OS national grid references (NGR)
|
|
@@ -8,16 +9,17 @@ export class OsGridRefField extends LocationFieldBase {
|
|
|
8
9
|
// - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345
|
|
9
10
|
// Optional spaces between each block
|
|
10
11
|
const pattern = /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{3})\s?([0-9]{3})|([0-9]{4})\s?([0-9]{4})|([0-9]{5})\s?([0-9]{5}))$/;
|
|
12
|
+
const patternTemplate = 'Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456';
|
|
11
13
|
return {
|
|
12
14
|
pattern,
|
|
13
|
-
patternErrorMessage:
|
|
14
|
-
requiredMessage: 'Enter {{#title}}'
|
|
15
|
+
patternErrorMessage: createLowerFirstExpression(patternTemplate),
|
|
16
|
+
requiredMessage: createLowerFirstExpression('Enter {{lowerFirst(#title)}}')
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
19
|
getErrorTemplates() {
|
|
18
20
|
return [{
|
|
19
21
|
type: 'pattern',
|
|
20
|
-
template: 'Enter a valid OS grid reference for {{#title}} like TQ123456'
|
|
22
|
+
template: createLowerFirstExpression('Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456')
|
|
21
23
|
}];
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OsGridRefField.js","names":["LocationFieldBase","OsGridRefField","getValidationConfig","pattern","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","instance","Object","create","prototype"],"sources":["../../../../../src/server/plugins/engine/components/OsGridRefField.ts"],"sourcesContent":["import { type OsGridRefFieldComponent } from '@defra/forms-model'\n\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\n\nexport class OsGridRefField extends LocationFieldBase {\n declare options: OsGridRefFieldComponent['options']\n\n protected getValidationConfig() {\n // Regex for OS national grid references (NGR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n // - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345\n // Optional spaces between each block\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?(([0-9]{3})\\s?([0-9]{3})|([0-9]{4})\\s?([0-9]{4})|([0-9]{5})\\s?([0-9]{5}))$/\n\n
|
|
1
|
+
{"version":3,"file":"OsGridRefField.js","names":["LocationFieldBase","createLowerFirstExpression","OsGridRefField","getValidationConfig","pattern","patternTemplate","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","instance","Object","create","prototype"],"sources":["../../../../../src/server/plugins/engine/components/OsGridRefField.ts"],"sourcesContent":["import { type OsGridRefFieldComponent } from '@defra/forms-model'\n\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nexport class OsGridRefField extends LocationFieldBase {\n declare options: OsGridRefFieldComponent['options']\n\n protected getValidationConfig() {\n // Regex for OS national grid references (NGR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n // - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345\n // Optional spaces between each block\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?(([0-9]{3})\\s?([0-9]{3})|([0-9]{4})\\s?([0-9]{4})|([0-9]{5})\\s?([0-9]{5}))$/\n\n const patternTemplate =\n 'Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456'\n\n return {\n pattern,\n patternErrorMessage: createLowerFirstExpression(patternTemplate),\n requiredMessage: createLowerFirstExpression(\n 'Enter {{lowerFirst(#title)}}'\n )\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n 'Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456'\n )\n }\n ]\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors() {\n const instance = Object.create(OsGridRefField.prototype) as OsGridRefField\n return instance.getAllPossibleErrors()\n }\n}\n"],"mappings":"AAEA,SAASA,iBAAiB;AAC1B,SAASC,0BAA0B;AAEnC,OAAO,MAAMC,cAAc,SAASF,iBAAiB,CAAC;EAG1CG,mBAAmBA,CAAA,EAAG;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA,MAAMC,OAAO,GACX,qLAAqL;IAEvL,MAAMC,eAAe,GACnB,0EAA0E;IAE5E,OAAO;MACLD,OAAO;MACPE,mBAAmB,EAAEL,0BAA0B,CAACI,eAAe,CAAC;MAChEE,eAAe,EAAEN,0BAA0B,CACzC,8BACF;IACF,CAAC;EACH;EAEUO,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EAAET,0BAA0B,CAClC,0EACF;IACF,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOU,oBAAoBA,CAAA,EAAG;IAC5B,MAAMC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAACZ,cAAc,CAACa,SAAS,CAAmB;IAC1E,OAAOH,QAAQ,CAACD,oBAAoB,CAAC,CAAC;EACxC;AACF","ignoreList":[]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ComponentDef } from '@defra/forms-model';
|
|
2
|
+
import { type JoiExpression, type ReferenceOptions } from 'joi';
|
|
2
3
|
/**
|
|
3
4
|
* Prevent Markdown formatting
|
|
4
5
|
* @see {@link https://pandoc.org/chunkedhtml-demo/8.11-backslash-escapes.html}
|
|
@@ -9,3 +10,12 @@ export declare const addClassOptionIfNone: (options: Extract<ComponentDef, {
|
|
|
9
10
|
classes?: string;
|
|
10
11
|
};
|
|
11
12
|
}>["options"], className: string) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for Joi expressions that use lowerFirst function
|
|
15
|
+
*/
|
|
16
|
+
export declare const lowerFirstExpressionOptions: ReferenceOptions;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a Joi expression with lowerFirst function support
|
|
19
|
+
* Used for error messages in location field components
|
|
20
|
+
*/
|
|
21
|
+
export declare const createLowerFirstExpression: (template: string) => JoiExpression;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
import lowerFirst from 'lodash/lowerFirst.js';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Prevent Markdown formatting
|
|
3
6
|
* @see {@link https://pandoc.org/chunkedhtml-demo/8.11-backslash-escapes.html}
|
|
@@ -12,4 +15,19 @@ export function escapeMarkdown(answer) {
|
|
|
12
15
|
export const addClassOptionIfNone = (options, className) => {
|
|
13
16
|
options.classes ??= className;
|
|
14
17
|
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for Joi expressions that use lowerFirst function
|
|
21
|
+
*/
|
|
22
|
+
export const lowerFirstExpressionOptions = {
|
|
23
|
+
functions: {
|
|
24
|
+
lowerFirst
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a Joi expression with lowerFirst function support
|
|
30
|
+
* Used for error messages in location field components
|
|
31
|
+
*/
|
|
32
|
+
export const createLowerFirstExpression = template => joi.expression(template, lowerFirstExpressionOptions);
|
|
15
33
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["escapeMarkdown","answer","punctuation","character","replaceAll","addClassOptionIfNone","options","className","classes"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/index.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\n\n/**\n * Prevent Markdown formatting\n * @see {@link https://pandoc.org/chunkedhtml-demo/8.11-backslash-escapes.html}\n */\nexport function escapeMarkdown(answer: string) {\n const punctuation = [\n '`',\n \"'\",\n '*',\n '_',\n '{',\n '}',\n '[',\n ']',\n '(',\n ')',\n '#',\n '+',\n '-',\n '.',\n '!'\n ]\n\n for (const character of punctuation) {\n answer = answer.replaceAll(character, `\\\\${character}`)\n }\n\n return answer\n}\n\nexport const addClassOptionIfNone = (\n options: Extract<ComponentDef, { options: { classes?: string } }>['options'],\n className: string\n) => {\n options.classes ??= className\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":["joi","lowerFirst","escapeMarkdown","answer","punctuation","character","replaceAll","addClassOptionIfNone","options","className","classes","lowerFirstExpressionOptions","functions","createLowerFirstExpression","template","expression"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/index.ts"],"sourcesContent":["import { type ComponentDef } from '@defra/forms-model'\nimport joi, { type JoiExpression, type ReferenceOptions } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\n/**\n * Prevent Markdown formatting\n * @see {@link https://pandoc.org/chunkedhtml-demo/8.11-backslash-escapes.html}\n */\nexport function escapeMarkdown(answer: string) {\n const punctuation = [\n '`',\n \"'\",\n '*',\n '_',\n '{',\n '}',\n '[',\n ']',\n '(',\n ')',\n '#',\n '+',\n '-',\n '.',\n '!'\n ]\n\n for (const character of punctuation) {\n answer = answer.replaceAll(character, `\\\\${character}`)\n }\n\n return answer\n}\n\nexport const addClassOptionIfNone = (\n options: Extract<ComponentDef, { options: { classes?: string } }>['options'],\n className: string\n) => {\n options.classes ??= className\n}\n\n/**\n * Configuration for Joi expressions that use lowerFirst function\n */\nexport const lowerFirstExpressionOptions = {\n functions: {\n lowerFirst\n }\n} as ReferenceOptions\n\n/**\n * Creates a Joi expression with lowerFirst function support\n * Used for error messages in location field components\n */\nexport const createLowerFirstExpression = (template: string): JoiExpression =>\n joi.expression(template, lowerFirstExpressionOptions) as JoiExpression\n"],"mappings":"AACA,OAAOA,GAAG,MAAqD,KAAK;AACpE,OAAOC,UAAU,MAAM,sBAAsB;;AAE7C;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAACC,MAAc,EAAE;EAC7C,MAAMC,WAAW,GAAG,CAClB,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,CACJ;EAED,KAAK,MAAMC,SAAS,IAAID,WAAW,EAAE;IACnCD,MAAM,GAAGA,MAAM,CAACG,UAAU,CAACD,SAAS,EAAE,KAAKA,SAAS,EAAE,CAAC;EACzD;EAEA,OAAOF,MAAM;AACf;AAEA,OAAO,MAAMI,oBAAoB,GAAGA,CAClCC,OAA4E,EAC5EC,SAAiB,KACd;EACHD,OAAO,CAACE,OAAO,KAAKD,SAAS;AAC/B,CAAC;;AAED;AACA;AACA;AACA,OAAO,MAAME,2BAA2B,GAAG;EACzCC,SAAS,EAAE;IACTX;EACF;AACF,CAAqB;;AAErB;AACA;AACA;AACA;AACA,OAAO,MAAMY,0BAA0B,GAAIC,QAAgB,IACzDd,GAAG,CAACe,UAAU,CAACD,QAAQ,EAAEH,2BAA2B,CAAkB","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -416,7 +416,36 @@ describe('EastingNorthingField', () => {
|
|
|
416
416
|
const staticResult = EastingNorthingField.getAllPossibleErrors()
|
|
417
417
|
const instanceResult = field.getAllPossibleErrors()
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
// Compare structure and content
|
|
420
|
+
expect(instanceResult.baseErrors).toHaveLength(
|
|
421
|
+
staticResult.baseErrors.length
|
|
422
|
+
)
|
|
423
|
+
expect(instanceResult.advancedSettingsErrors).toHaveLength(
|
|
424
|
+
staticResult.advancedSettingsErrors.length
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
// Compare error types
|
|
428
|
+
expect(instanceResult.baseErrors.map((e) => e.type)).toEqual(
|
|
429
|
+
staticResult.baseErrors.map((e) => e.type)
|
|
430
|
+
)
|
|
431
|
+
expect(
|
|
432
|
+
instanceResult.advancedSettingsErrors.map((e) => e.type)
|
|
433
|
+
).toEqual(staticResult.advancedSettingsErrors.map((e) => e.type))
|
|
434
|
+
|
|
435
|
+
// Compare rendered templates
|
|
436
|
+
expect(
|
|
437
|
+
instanceResult.baseErrors.map((e) =>
|
|
438
|
+
typeof e.template === 'object' && 'rendered' in e.template
|
|
439
|
+
? e.template.rendered
|
|
440
|
+
: e.template
|
|
441
|
+
)
|
|
442
|
+
).toEqual(
|
|
443
|
+
staticResult.baseErrors.map((e) =>
|
|
444
|
+
typeof e.template === 'object' && 'rendered' in e.template
|
|
445
|
+
? e.template.rendered
|
|
446
|
+
: e.template
|
|
447
|
+
)
|
|
448
|
+
)
|
|
420
449
|
})
|
|
421
450
|
})
|
|
422
451
|
})
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getLocationFieldViewModel
|
|
16
16
|
} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'
|
|
17
17
|
import { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'
|
|
18
|
+
import { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
18
19
|
import { type EastingNorthingState } from '~/src/server/plugins/engine/components/types.js'
|
|
19
20
|
import { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'
|
|
20
21
|
import {
|
|
@@ -198,29 +199,41 @@ export class EastingNorthingField extends FormComponent {
|
|
|
198
199
|
{ type: 'required', template: messageTemplate.required },
|
|
199
200
|
{
|
|
200
201
|
type: 'eastingFormat',
|
|
201
|
-
template:
|
|
202
|
+
template: createLowerFirstExpression(
|
|
203
|
+
'Easting for {{lowerFirst(#title)}} must be between 1 and 6 digits'
|
|
204
|
+
)
|
|
202
205
|
},
|
|
203
206
|
{
|
|
204
207
|
type: 'northingFormat',
|
|
205
|
-
template:
|
|
208
|
+
template: createLowerFirstExpression(
|
|
209
|
+
'Northing for {{lowerFirst(#title)}} must be between 1 and 7 digits'
|
|
210
|
+
)
|
|
206
211
|
}
|
|
207
212
|
],
|
|
208
213
|
advancedSettingsErrors: [
|
|
209
214
|
{
|
|
210
215
|
type: 'eastingMin',
|
|
211
|
-
template:
|
|
216
|
+
template: createLowerFirstExpression(
|
|
217
|
+
`Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`
|
|
218
|
+
)
|
|
212
219
|
},
|
|
213
220
|
{
|
|
214
221
|
type: 'eastingMax',
|
|
215
|
-
template:
|
|
222
|
+
template: createLowerFirstExpression(
|
|
223
|
+
`Easting for {{lowerFirst(#title)}} must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}`
|
|
224
|
+
)
|
|
216
225
|
},
|
|
217
226
|
{
|
|
218
227
|
type: 'northingMin',
|
|
219
|
-
template:
|
|
228
|
+
template: createLowerFirstExpression(
|
|
229
|
+
`Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`
|
|
230
|
+
)
|
|
220
231
|
},
|
|
221
232
|
{
|
|
222
233
|
type: 'northingMax',
|
|
223
|
-
template:
|
|
234
|
+
template: createLowerFirstExpression(
|
|
235
|
+
`Northing for {{lowerFirst(#title)}} must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`
|
|
236
|
+
)
|
|
224
237
|
}
|
|
225
238
|
]
|
|
226
239
|
}
|
|
@@ -404,7 +404,36 @@ describe('LatLongField', () => {
|
|
|
404
404
|
const staticResult = LatLongField.getAllPossibleErrors()
|
|
405
405
|
const instanceResult = field.getAllPossibleErrors()
|
|
406
406
|
|
|
407
|
-
|
|
407
|
+
// Compare structure and content
|
|
408
|
+
expect(instanceResult.baseErrors).toHaveLength(
|
|
409
|
+
staticResult.baseErrors.length
|
|
410
|
+
)
|
|
411
|
+
expect(instanceResult.advancedSettingsErrors).toHaveLength(
|
|
412
|
+
staticResult.advancedSettingsErrors.length
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
// Compare error types
|
|
416
|
+
expect(instanceResult.baseErrors.map((e) => e.type)).toEqual(
|
|
417
|
+
staticResult.baseErrors.map((e) => e.type)
|
|
418
|
+
)
|
|
419
|
+
expect(
|
|
420
|
+
instanceResult.advancedSettingsErrors.map((e) => e.type)
|
|
421
|
+
).toEqual(staticResult.advancedSettingsErrors.map((e) => e.type))
|
|
422
|
+
|
|
423
|
+
// Compare rendered templates
|
|
424
|
+
expect(
|
|
425
|
+
instanceResult.baseErrors.map((e) =>
|
|
426
|
+
typeof e.template === 'object' && 'rendered' in e.template
|
|
427
|
+
? e.template.rendered
|
|
428
|
+
: e.template
|
|
429
|
+
)
|
|
430
|
+
).toEqual(
|
|
431
|
+
staticResult.baseErrors.map((e) =>
|
|
432
|
+
typeof e.template === 'object' && 'rendered' in e.template
|
|
433
|
+
? e.template.rendered
|
|
434
|
+
: e.template
|
|
435
|
+
)
|
|
436
|
+
)
|
|
408
437
|
})
|
|
409
438
|
})
|
|
410
439
|
})
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getLocationFieldViewModel
|
|
13
13
|
} from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'
|
|
14
14
|
import { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'
|
|
15
|
+
import { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
15
16
|
import { type LatLongState } from '~/src/server/plugins/engine/components/types.js'
|
|
16
17
|
import { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'
|
|
17
18
|
import {
|
|
@@ -194,29 +195,41 @@ export class LatLongField extends FormComponent {
|
|
|
194
195
|
{ type: 'required', template: messageTemplate.required },
|
|
195
196
|
{
|
|
196
197
|
type: 'latitudeFormat',
|
|
197
|
-
template:
|
|
198
|
+
template: createLowerFirstExpression(
|
|
199
|
+
'Enter a valid latitude for {{lowerFirst(#title)}} like 51.519450'
|
|
200
|
+
)
|
|
198
201
|
},
|
|
199
202
|
{
|
|
200
203
|
type: 'longitudeFormat',
|
|
201
|
-
template:
|
|
204
|
+
template: createLowerFirstExpression(
|
|
205
|
+
'Enter a valid longitude for {{lowerFirst(#title)}} like -0.127758'
|
|
206
|
+
)
|
|
202
207
|
}
|
|
203
208
|
],
|
|
204
209
|
advancedSettingsErrors: [
|
|
205
210
|
{
|
|
206
211
|
type: 'latitudeMin',
|
|
207
|
-
template:
|
|
212
|
+
template: createLowerFirstExpression(
|
|
213
|
+
'Latitude for {{lowerFirst(#title)}} must be between 49 and 60'
|
|
214
|
+
)
|
|
208
215
|
},
|
|
209
216
|
{
|
|
210
217
|
type: 'latitudeMax',
|
|
211
|
-
template:
|
|
218
|
+
template: createLowerFirstExpression(
|
|
219
|
+
'Latitude for {{lowerFirst(#title)}} must be between 49 and 60'
|
|
220
|
+
)
|
|
212
221
|
},
|
|
213
222
|
{
|
|
214
223
|
type: 'longitudeMin',
|
|
215
|
-
template:
|
|
224
|
+
template: createLowerFirstExpression(
|
|
225
|
+
'Longitude for {{lowerFirst(#title)}} must be between -9 and 2'
|
|
226
|
+
)
|
|
216
227
|
},
|
|
217
228
|
{
|
|
218
229
|
type: 'longitudeMax',
|
|
219
|
-
template:
|
|
230
|
+
template: createLowerFirstExpression(
|
|
231
|
+
'Longitude for {{lowerFirst(#title)}} must be between -9 and 2'
|
|
232
|
+
)
|
|
220
233
|
}
|
|
221
234
|
]
|
|
222
235
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type FormComponentsDef } from '@defra/forms-model'
|
|
2
|
-
import joi, {
|
|
2
|
+
import joi, {
|
|
3
|
+
type JoiExpression,
|
|
4
|
+
type LanguageMessages,
|
|
5
|
+
type StringSchema
|
|
6
|
+
} from 'joi'
|
|
3
7
|
|
|
4
8
|
import {
|
|
5
9
|
FormComponent,
|
|
@@ -15,6 +19,7 @@ import {
|
|
|
15
19
|
type FormSubmissionError,
|
|
16
20
|
type FormSubmissionState
|
|
17
21
|
} from '~/src/server/plugins/engine/types.js'
|
|
22
|
+
import { convertToLanguageMessages } from '~/src/server/utils/type-utils.js'
|
|
18
23
|
|
|
19
24
|
interface LocationFieldOptions {
|
|
20
25
|
instructionText?: string
|
|
@@ -26,8 +31,8 @@ interface LocationFieldOptions {
|
|
|
26
31
|
|
|
27
32
|
interface ValidationConfig {
|
|
28
33
|
pattern: RegExp
|
|
29
|
-
patternErrorMessage:
|
|
30
|
-
requiredMessage?:
|
|
34
|
+
patternErrorMessage: JoiExpression
|
|
35
|
+
requiredMessage?: JoiExpression
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
/**
|
|
@@ -42,7 +47,7 @@ export abstract class LocationFieldBase extends FormComponent {
|
|
|
42
47
|
protected abstract getValidationConfig(): ValidationConfig
|
|
43
48
|
protected abstract getErrorTemplates(): {
|
|
44
49
|
type: string
|
|
45
|
-
template:
|
|
50
|
+
template: JoiExpression
|
|
46
51
|
}[]
|
|
47
52
|
|
|
48
53
|
constructor(
|
|
@@ -61,11 +66,11 @@ export abstract class LocationFieldBase extends FormComponent {
|
|
|
61
66
|
const requiredMessage =
|
|
62
67
|
config.requiredMessage ?? (messageTemplate.required as string)
|
|
63
68
|
|
|
64
|
-
const messages
|
|
69
|
+
const messages = convertToLanguageMessages({
|
|
65
70
|
'any.required': requiredMessage,
|
|
66
71
|
'string.empty': requiredMessage,
|
|
67
72
|
'string.pattern.base': config.patternErrorMessage
|
|
68
|
-
}
|
|
73
|
+
})
|
|
69
74
|
|
|
70
75
|
let formSchema = joi
|
|
71
76
|
.string()
|
|
@@ -129,7 +129,7 @@ describe('NationalGridFieldNumberField', () => {
|
|
|
129
129
|
|
|
130
130
|
expect(result.errors).toEqual([
|
|
131
131
|
expect.objectContaining({
|
|
132
|
-
text: 'Enter
|
|
132
|
+
text: 'Enter example National Grid field number'
|
|
133
133
|
})
|
|
134
134
|
])
|
|
135
135
|
})
|
|
@@ -293,7 +293,7 @@ describe('NationalGridFieldNumberField', () => {
|
|
|
293
293
|
value: getFormData('NG1234567'),
|
|
294
294
|
errors: expect.arrayContaining([
|
|
295
295
|
expect.objectContaining({
|
|
296
|
-
text: 'Enter a valid National Grid field number for
|
|
296
|
+
text: 'Enter a valid National Grid field number for grid field like NG 1234 5678'
|
|
297
297
|
})
|
|
298
298
|
])
|
|
299
299
|
}
|
|
@@ -304,7 +304,7 @@ describe('NationalGridFieldNumberField', () => {
|
|
|
304
304
|
value: getFormData('N123456789'),
|
|
305
305
|
errors: expect.arrayContaining([
|
|
306
306
|
expect.objectContaining({
|
|
307
|
-
text: 'Enter a valid National Grid field number for
|
|
307
|
+
text: 'Enter a valid National Grid field number for grid field like NG 1234 5678'
|
|
308
308
|
})
|
|
309
309
|
])
|
|
310
310
|
}
|
|
@@ -315,7 +315,7 @@ describe('NationalGridFieldNumberField', () => {
|
|
|
315
315
|
value: getFormData('NGABCDEFGH'),
|
|
316
316
|
errors: expect.arrayContaining([
|
|
317
317
|
expect.objectContaining({
|
|
318
|
-
text: 'Enter a valid National Grid field number for
|
|
318
|
+
text: 'Enter a valid National Grid field number for grid field like NG 1234 5678'
|
|
319
319
|
})
|
|
320
320
|
])
|
|
321
321
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'
|
|
4
|
+
import { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
4
5
|
|
|
5
6
|
export class NationalGridFieldNumberField extends LocationFieldBase {
|
|
6
7
|
declare options: NationalGridFieldNumberFieldComponent['options']
|
|
@@ -12,10 +13,15 @@ export class NationalGridFieldNumberField extends LocationFieldBase {
|
|
|
12
13
|
const pattern =
|
|
13
14
|
/^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?([0-9]{4})\s?([0-9]{4})$/
|
|
14
15
|
|
|
16
|
+
const patternTemplate =
|
|
17
|
+
'Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678'
|
|
18
|
+
|
|
15
19
|
return {
|
|
16
20
|
pattern,
|
|
17
|
-
patternErrorMessage:
|
|
18
|
-
requiredMessage:
|
|
21
|
+
patternErrorMessage: createLowerFirstExpression(patternTemplate),
|
|
22
|
+
requiredMessage: createLowerFirstExpression(
|
|
23
|
+
'Enter {{lowerFirst(#title)}}'
|
|
24
|
+
)
|
|
19
25
|
}
|
|
20
26
|
}
|
|
21
27
|
|
|
@@ -23,8 +29,9 @@ export class NationalGridFieldNumberField extends LocationFieldBase {
|
|
|
23
29
|
return [
|
|
24
30
|
{
|
|
25
31
|
type: 'pattern',
|
|
26
|
-
template:
|
|
27
|
-
'Enter a valid National Grid field number for {{#title}} like NG 1234 5678'
|
|
32
|
+
template: createLowerFirstExpression(
|
|
33
|
+
'Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678'
|
|
34
|
+
)
|
|
28
35
|
}
|
|
29
36
|
]
|
|
30
37
|
}
|
|
@@ -135,7 +135,7 @@ describe('OsGridRefField', () => {
|
|
|
135
135
|
|
|
136
136
|
expect(result.errors).toEqual([
|
|
137
137
|
expect.objectContaining({
|
|
138
|
-
text: 'Enter
|
|
138
|
+
text: 'Enter example OS grid reference'
|
|
139
139
|
})
|
|
140
140
|
])
|
|
141
141
|
})
|
|
@@ -308,7 +308,7 @@ describe('OsGridRefField', () => {
|
|
|
308
308
|
value: getFormData('TQ12345'),
|
|
309
309
|
errors: expect.arrayContaining([
|
|
310
310
|
expect.objectContaining({
|
|
311
|
-
text: 'Enter a valid OS grid reference for
|
|
311
|
+
text: 'Enter a valid OS grid reference for grid reference like TQ123456'
|
|
312
312
|
})
|
|
313
313
|
])
|
|
314
314
|
}
|
|
@@ -319,7 +319,7 @@ describe('OsGridRefField', () => {
|
|
|
319
319
|
value: getFormData('AA1234567'),
|
|
320
320
|
errors: expect.arrayContaining([
|
|
321
321
|
expect.objectContaining({
|
|
322
|
-
text: 'Enter a valid OS grid reference for
|
|
322
|
+
text: 'Enter a valid OS grid reference for grid reference like TQ123456'
|
|
323
323
|
})
|
|
324
324
|
])
|
|
325
325
|
}
|
|
@@ -330,7 +330,7 @@ describe('OsGridRefField', () => {
|
|
|
330
330
|
value: getFormData('TQABCDEF'),
|
|
331
331
|
errors: expect.arrayContaining([
|
|
332
332
|
expect.objectContaining({
|
|
333
|
-
text: 'Enter a valid OS grid reference for
|
|
333
|
+
text: 'Enter a valid OS grid reference for grid reference like TQ123456'
|
|
334
334
|
})
|
|
335
335
|
])
|
|
336
336
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type OsGridRefFieldComponent } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'
|
|
4
|
+
import { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
4
5
|
|
|
5
6
|
export class OsGridRefField extends LocationFieldBase {
|
|
6
7
|
declare options: OsGridRefFieldComponent['options']
|
|
@@ -15,10 +16,15 @@ export class OsGridRefField extends LocationFieldBase {
|
|
|
15
16
|
const pattern =
|
|
16
17
|
/^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{3})\s?([0-9]{3})|([0-9]{4})\s?([0-9]{4})|([0-9]{5})\s?([0-9]{5}))$/
|
|
17
18
|
|
|
19
|
+
const patternTemplate =
|
|
20
|
+
'Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456'
|
|
21
|
+
|
|
18
22
|
return {
|
|
19
23
|
pattern,
|
|
20
|
-
patternErrorMessage:
|
|
21
|
-
requiredMessage:
|
|
24
|
+
patternErrorMessage: createLowerFirstExpression(patternTemplate),
|
|
25
|
+
requiredMessage: createLowerFirstExpression(
|
|
26
|
+
'Enter {{lowerFirst(#title)}}'
|
|
27
|
+
)
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
|
|
@@ -26,7 +32,9 @@ export class OsGridRefField extends LocationFieldBase {
|
|
|
26
32
|
return [
|
|
27
33
|
{
|
|
28
34
|
type: 'pattern',
|
|
29
|
-
template:
|
|
35
|
+
template: createLowerFirstExpression(
|
|
36
|
+
'Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456'
|
|
37
|
+
)
|
|
30
38
|
}
|
|
31
39
|
]
|
|
32
40
|
}
|
|
@@ -6,6 +6,10 @@ import { LatLongField } from '~/src/server/plugins/engine/components/LatLongFiel
|
|
|
6
6
|
import { NationalGridFieldNumberField } from '~/src/server/plugins/engine/components/NationalGridFieldNumberField.js'
|
|
7
7
|
import { OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'
|
|
8
8
|
import { createComponent } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
9
|
+
import {
|
|
10
|
+
createLowerFirstExpression,
|
|
11
|
+
lowerFirstExpressionOptions
|
|
12
|
+
} from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
9
13
|
import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
10
14
|
import definition from '~/test/form/definitions/basic.js'
|
|
11
15
|
|
|
@@ -123,3 +127,39 @@ describe('ComponentBase tests', () => {
|
|
|
123
127
|
expect(component.title).toBe('Context Field')
|
|
124
128
|
})
|
|
125
129
|
})
|
|
130
|
+
|
|
131
|
+
describe('lowerFirst expression helpers', () => {
|
|
132
|
+
test('lowerFirstExpressionOptions should have lowerFirst function', () => {
|
|
133
|
+
expect(lowerFirstExpressionOptions).toHaveProperty('functions')
|
|
134
|
+
expect(lowerFirstExpressionOptions).toHaveProperty(
|
|
135
|
+
'functions.lowerFirst',
|
|
136
|
+
expect.any(Function)
|
|
137
|
+
)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('createLowerFirstExpression should create a Joi expression', () => {
|
|
141
|
+
const template = 'Enter {{lowerFirst(#title)}}'
|
|
142
|
+
const expression = createLowerFirstExpression(template)
|
|
143
|
+
|
|
144
|
+
expect(expression).toBeDefined()
|
|
145
|
+
expect(typeof expression).toBe('object')
|
|
146
|
+
expect(expression).toHaveProperty('_template')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('createLowerFirstExpression should render template with lowerFirst', () => {
|
|
150
|
+
const template = 'Enter {{lowerFirst(#title)}}'
|
|
151
|
+
const expression = createLowerFirstExpression(template)
|
|
152
|
+
|
|
153
|
+
// Check the rendered template is stored
|
|
154
|
+
expect(expression).toHaveProperty('rendered', template)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('createLowerFirstExpression should support multiple interpolations', () => {
|
|
158
|
+
const template =
|
|
159
|
+
'Easting for {{lowerFirst(#title)}} must be between {{#min}} and {{#max}}'
|
|
160
|
+
const expression = createLowerFirstExpression(template)
|
|
161
|
+
|
|
162
|
+
expect(expression).toBeDefined()
|
|
163
|
+
expect(expression).toHaveProperty('rendered', template)
|
|
164
|
+
})
|
|
165
|
+
})
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ComponentDef } from '@defra/forms-model'
|
|
2
|
+
import joi, { type JoiExpression, type ReferenceOptions } from 'joi'
|
|
3
|
+
import lowerFirst from 'lodash/lowerFirst.js'
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Prevent Markdown formatting
|
|
@@ -36,3 +38,19 @@ export const addClassOptionIfNone = (
|
|
|
36
38
|
) => {
|
|
37
39
|
options.classes ??= className
|
|
38
40
|
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Configuration for Joi expressions that use lowerFirst function
|
|
44
|
+
*/
|
|
45
|
+
export const lowerFirstExpressionOptions = {
|
|
46
|
+
functions: {
|
|
47
|
+
lowerFirst
|
|
48
|
+
}
|
|
49
|
+
} as ReferenceOptions
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a Joi expression with lowerFirst function support
|
|
53
|
+
* Used for error messages in location field components
|
|
54
|
+
*/
|
|
55
|
+
export const createLowerFirstExpression = (template: string): JoiExpression =>
|
|
56
|
+
joi.expression(template, lowerFirstExpressionOptions) as JoiExpression
|