@defra/forms-engine-plugin 4.0.11 → 4.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +2 -2
  2. package/.server/server/plugins/engine/components/EastingNorthingField.js +4 -24
  3. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  4. package/.server/server/plugins/engine/components/LatLongField.js +8 -31
  5. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  6. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +1 -3
  7. package/.server/server/plugins/engine/components/LocationFieldBase.js +1 -8
  8. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  9. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +0 -2
  10. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +7 -18
  11. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  12. package/.server/server/plugins/engine/components/NumberField.d.ts +0 -18
  13. package/.server/server/plugins/engine/components/NumberField.js +2 -103
  14. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  15. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +0 -2
  16. package/.server/server/plugins/engine/components/OsGridRefField.js +4 -32
  17. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  18. package/.server/server/plugins/engine/models/FormModel.d.ts +2 -2
  19. package/.server/server/plugins/engine/models/FormModel.js +1 -1
  20. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  21. package/.server/server/plugins/engine/models/types.d.ts +1 -1
  22. package/.server/server/plugins/engine/models/types.js.map +1 -1
  23. package/package.json +2 -2
  24. package/src/server/forms/register-as-a-unicorn-breeder.yaml +2 -2
  25. package/src/server/plugins/engine/components/EastingNorthingField.test.ts +0 -14
  26. package/src/server/plugins/engine/components/EastingNorthingField.ts +4 -24
  27. package/src/server/plugins/engine/components/LatLongField.test.ts +4 -24
  28. package/src/server/plugins/engine/components/LatLongField.ts +8 -33
  29. package/src/server/plugins/engine/components/LocationFieldBase.ts +1 -15
  30. package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +22 -8
  31. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -20
  32. package/src/server/plugins/engine/components/NumberField.test.ts +12 -504
  33. package/src/server/plugins/engine/components/NumberField.ts +4 -133
  34. package/src/server/plugins/engine/components/OsGridRefField.test.ts +11 -33
  35. package/src/server/plugins/engine/components/OsGridRefField.ts +5 -38
  36. package/src/server/plugins/engine/models/FormModel.ts +1 -1
  37. package/src/server/plugins/engine/models/types.ts +1 -1
@@ -203,7 +203,7 @@ pages:
203
203
  path: '/how-many-members-of-staff-will-look-after-the-unicorns'
204
204
  section: susaYr
205
205
  next:
206
- - path: '/summary'
206
+ - path: '/declaration'
207
207
  components:
208
208
  - name: zhJMaM
209
209
  options:
@@ -219,7 +219,7 @@ pages:
219
219
  controller: FileUploadPageController
220
220
  section: Regnsa
221
221
  next:
222
- - path: '/declaration'
222
+ - path: '/how-many-unicorns-do-you-expect-to-breed-each-year'
223
223
  components:
224
224
  - name: dLzALM
225
225
  title: Documents
@@ -11,18 +11,6 @@ const DEFAULT_EASTING_MIN = 0;
11
11
  const DEFAULT_EASTING_MAX = 700000;
12
12
  const DEFAULT_NORTHING_MIN = 0;
13
13
  const DEFAULT_NORTHING_MAX = 1300000;
14
-
15
- // Easting length constraints (integer values only, no decimals)
16
- // Min: 1 char for values like "0" or single digit values
17
- // Max: 6 chars for values up to 700000 (British National Grid easting limit)
18
- const EASTING_MIN_LENGTH = 1;
19
- const EASTING_MAX_LENGTH = 6;
20
-
21
- // Northing length constraints (integer values only, no decimals)
22
- // Min: 1 char for values like "0" or single digit values
23
- // Max: 7 chars for values up to 1300000 (British National Grid northing limit)
24
- const NORTHING_MIN_LENGTH = 1;
25
- const NORTHING_MAX_LENGTH = 7;
26
14
  export class EastingNorthingField extends FormComponent {
27
15
  constructor(def, props) {
28
16
  super(def, props);
@@ -43,9 +31,7 @@ export class EastingNorthingField extends FormComponent {
43
31
  'number.max': `{{#label}} for ${this.title} must be between ${eastingMin} and {{#limit}}`,
44
32
  'number.precision': `{{#label}} for ${this.title} must be between 1 and 6 digits`,
45
33
  'number.integer': `{{#label}} for ${this.title} must be between 1 and 6 digits`,
46
- 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 6 digits`,
47
- 'number.minLength': `{{#label}} for ${this.title} must be between 1 and 6 digits`,
48
- 'number.maxLength': `{{#label}} for ${this.title} must be between 1 and 6 digits`
34
+ 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 6 digits`
49
35
  });
50
36
  const northingValidationMessages = convertToLanguageMessages({
51
37
  'any.required': messageTemplate.objectMissing,
@@ -54,9 +40,7 @@ export class EastingNorthingField extends FormComponent {
54
40
  'number.max': `{{#label}} for ${this.title} must be between ${northingMin} and {{#limit}}`,
55
41
  'number.precision': `{{#label}} for ${this.title} must be between 1 and 7 digits`,
56
42
  'number.integer': `{{#label}} for ${this.title} must be between 1 and 7 digits`,
57
- 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 7 digits`,
58
- 'number.minLength': `{{#label}} for ${this.title} must be between 1 and 7 digits`,
59
- 'number.maxLength': `{{#label}} for ${this.title} must be between 1 and 7 digits`
43
+ 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 7 digits`
60
44
  });
61
45
  this.collection = new ComponentCollection([{
62
46
  type: ComponentType.NumberField,
@@ -65,9 +49,7 @@ export class EastingNorthingField extends FormComponent {
65
49
  schema: {
66
50
  min: eastingMin,
67
51
  max: eastingMax,
68
- precision: 0,
69
- minLength: EASTING_MIN_LENGTH,
70
- maxLength: EASTING_MAX_LENGTH
52
+ precision: 0
71
53
  },
72
54
  options: {
73
55
  required: isRequired,
@@ -82,9 +64,7 @@ export class EastingNorthingField extends FormComponent {
82
64
  schema: {
83
65
  min: northingMin,
84
66
  max: northingMax,
85
- precision: 0,
86
- minLength: NORTHING_MIN_LENGTH,
87
- maxLength: NORTHING_MAX_LENGTH
67
+ precision: 0
88
68
  },
89
69
  options: {
90
70
  required: isRequired,
@@ -1 +1 @@
1
- {"version":3,"file":"EastingNorthingField.js","names":["ComponentType","ComponentCollection","FormComponent","isFormState","createLocationFieldValidator","getLocationFieldViewModel","NumberField","messageTemplate","convertToLanguageMessages","DEFAULT_EASTING_MIN","DEFAULT_EASTING_MAX","DEFAULT_NORTHING_MIN","DEFAULT_NORTHING_MAX","EASTING_MIN_LENGTH","EASTING_MAX_LENGTH","NORTHING_MIN_LENGTH","NORTHING_MAX_LENGTH","EastingNorthingField","constructor","def","props","name","options","schema","isRequired","required","eastingMin","easting","min","eastingMax","max","northingMin","northing","northingMax","customValidationMessages","objectMissing","title","northingValidationMessages","collection","type","precision","minLength","maxLength","optionalText","classes","parent","custom","getValidatorEastingNorthing","peers","formSchema","stateSchema","getFormValueFromState","state","value","isEastingNorthing","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber","component"],"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'\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 createLocationFieldValidator,\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\n// Easting length constraints (integer values only, no decimals)\n// Min: 1 char for values like \"0\" or single digit values\n// Max: 6 chars for values up to 700000 (British National Grid easting limit)\nconst EASTING_MIN_LENGTH = 1\nconst EASTING_MAX_LENGTH = 6\n\n// Northing length constraints (integer values only, no decimals)\n// Min: 1 char for values like \"0\" or single digit values\n// Max: 7 chars for values up to 1300000 (British National Grid northing limit)\nconst NORTHING_MIN_LENGTH = 1\nconst NORTHING_MAX_LENGTH = 7\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 customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${eastingMax}`,\n 'number.max': `{{#label}} for ${this.title} must be between ${eastingMin} and {{#limit}}`,\n 'number.precision': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.integer': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.minLength': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.maxLength': `{{#label}} for ${this.title} must be between 1 and 6 digits`\n })\n\n const northingValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${northingMax}`,\n 'number.max': `{{#label}} for ${this.title} must be between ${northingMin} and {{#limit}}`,\n 'number.precision': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.integer': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.minLength': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.maxLength': `{{#label}} for ${this.title} must be between 1 and 7 digits`\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 minLength: EASTING_MIN_LENGTH,\n maxLength: EASTING_MAX_LENGTH\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 minLength: NORTHING_MIN_LENGTH,\n maxLength: NORTHING_MAX_LENGTH\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 custom: getValidatorEastingNorthing(this),\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: <<northingvalue, eastingvalue>>\n return `${value.northing}, ${value.easting}`\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 // Output format: Northing: <<entry>>\\nEasting: <<entry>>\n return `Northing: ${value.northing}\\nEasting: ${value.easting}`\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 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:\n 'Easting for [short description] must be between 1 and 6 digits'\n },\n {\n type: 'northingFormat',\n template:\n 'Northing for [short description] must be between 1 and 7 digits'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'eastingMin',\n template: `Easting for [short description] must be between 0 and 700000`\n },\n {\n type: 'eastingMax',\n template: `Easting for [short description] must be between 0 and 700000`\n },\n {\n type: 'northingMin',\n template: `Northing for [short description] must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n },\n {\n type: 'northingMax',\n template: `Northing for [short description] 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\nexport function getValidatorEastingNorthing(component: EastingNorthingField) {\n return createLocationFieldValidator(component)\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"EastingNorthingField.js","names":["ComponentType","ComponentCollection","FormComponent","isFormState","createLocationFieldValidator","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","customValidationMessages","objectMissing","title","northingValidationMessages","collection","type","precision","optionalText","classes","parent","custom","getValidatorEastingNorthing","peers","formSchema","stateSchema","getFormValueFromState","state","value","isEastingNorthing","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber","component"],"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'\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 createLocationFieldValidator,\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 customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${eastingMax}`,\n 'number.max': `{{#label}} for ${this.title} must be between ${eastingMin} and {{#limit}}`,\n 'number.precision': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.integer': `{{#label}} for ${this.title} must be between 1 and 6 digits`,\n 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 6 digits`\n })\n\n const northingValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${northingMax}`,\n 'number.max': `{{#label}} for ${this.title} must be between ${northingMin} and {{#limit}}`,\n 'number.precision': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.integer': `{{#label}} for ${this.title} must be between 1 and 7 digits`,\n 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 7 digits`\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 custom: getValidatorEastingNorthing(this),\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: <<northingvalue, eastingvalue>>\n return `${value.northing}, ${value.easting}`\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 // Output format: Northing: <<entry>>\\nEasting: <<entry>>\n return `Northing: ${value.northing}\\nEasting: ${value.easting}`\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 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:\n 'Easting for [short description] must be between 1 and 6 digits'\n },\n {\n type: 'northingFormat',\n template:\n 'Northing for [short description] must be between 1 and 7 digits'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'eastingMin',\n template: `Easting for [short description] must be between 0 and 700000`\n },\n {\n type: 'eastingMax',\n template: `Easting for [short description] must be between 0 and 700000`\n },\n {\n type: 'northingMin',\n template: `Northing for [short description] must be between ${DEFAULT_NORTHING_MIN} and ${DEFAULT_NORTHING_MAX}`\n },\n {\n type: 'northingMax',\n template: `Northing for [short description] 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\nexport function getValidatorEastingNorthing(component: EastingNorthingField) {\n return createLocationFieldValidator(component)\n}\n"],"mappings":"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","ignoreList":[]}
@@ -9,19 +9,7 @@ import { convertToLanguageMessages } from "../../../utils/type-utils.js";
9
9
  // Precision constants
10
10
  // UK latitude/longitude requires high precision for accurate location (within ~11mm)
11
11
  const DECIMAL_PRECISION = 7; // 7 decimal places
12
- const MIN_DECIMAL_PLACES = 1; // At least 1 decimal place required
13
12
 
14
- // Latitude length constraints
15
- // Min: 3 chars for values like "52.1" (2 digits + decimal + 1 decimal place)
16
- // Max: 10 chars for values like "59.1234567" (2 digits + decimal + 7 decimal places)
17
- const LATITUDE_MIN_LENGTH = 3;
18
- const LATITUDE_MAX_LENGTH = 10;
19
-
20
- // Longitude length constraints
21
- // Min: 2 chars for values like "-1" or single digit with decimal (needs min decimal places)
22
- // Max: 10 chars for values like "-1.1234567" (minus + 1 digit + decimal + 7 decimal places)
23
- const LONGITUDE_MIN_LENGTH = 2;
24
- const LONGITUDE_MAX_LENGTH = 10;
25
13
  export class LatLongField extends FormComponent {
26
14
  constructor(def, props) {
27
15
  super(def, props);
@@ -33,32 +21,27 @@ export class LatLongField extends FormComponent {
33
21
  const isRequired = options.required !== false;
34
22
 
35
23
  // Read schema values from def.schema with fallback defaults
36
- const latitudeMin = schema?.latitude?.min ?? 49;
37
- const latitudeMax = schema?.latitude?.max ?? 60;
38
- const longitudeMin = schema?.longitude?.min ?? -9;
39
- const longitudeMax = schema?.longitude?.max ?? 2;
24
+ const latitudeMin = schema?.latitude?.min ?? 49.85;
25
+ const latitudeMax = schema?.latitude?.max ?? 60.859;
26
+ const longitudeMin = schema?.longitude?.min ?? -13.687;
27
+ const longitudeMax = schema?.longitude?.max ?? 1.767;
40
28
  const customValidationMessages = convertToLanguageMessages({
41
29
  'any.required': messageTemplate.objectMissing,
42
30
  'number.base': messageTemplate.objectMissing,
43
31
  'number.precision': '{{#label}} must have no more than 7 decimal places',
44
- 'number.minPrecision': '{{#label}} must have at least {{#minPrecision}} decimal place',
45
32
  'number.unsafe': '{{#label}} must be a valid number'
46
33
  });
47
34
  const latitudeMessages = convertToLanguageMessages({
48
35
  ...customValidationMessages,
49
36
  'number.base': `Enter a valid latitude for ${this.title} like 51.519450`,
50
37
  'number.min': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`,
51
- 'number.max': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`,
52
- 'number.minLength': `Latitude for ${this.title} must be between 3 and 10 characters`,
53
- 'number.maxLength': `Latitude for ${this.title} must be between 3 and 10 characters`
38
+ 'number.max': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`
54
39
  });
55
40
  const longitudeMessages = convertToLanguageMessages({
56
41
  ...customValidationMessages,
57
42
  'number.base': `Enter a valid longitude for ${this.title} like -0.127758`,
58
43
  'number.min': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`,
59
- 'number.max': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`,
60
- 'number.minLength': `Longitude for ${this.title} must be between 2 and 10 characters`,
61
- 'number.maxLength': `Longitude for ${this.title} must be between 2 and 10 characters`
44
+ 'number.max': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`
62
45
  });
63
46
  this.collection = new ComponentCollection([{
64
47
  type: ComponentType.NumberField,
@@ -67,10 +50,7 @@ export class LatLongField extends FormComponent {
67
50
  schema: {
68
51
  min: latitudeMin,
69
52
  max: latitudeMax,
70
- precision: DECIMAL_PRECISION,
71
- minPrecision: MIN_DECIMAL_PLACES,
72
- minLength: LATITUDE_MIN_LENGTH,
73
- maxLength: LATITUDE_MAX_LENGTH
53
+ precision: DECIMAL_PRECISION
74
54
  },
75
55
  options: {
76
56
  required: isRequired,
@@ -86,10 +66,7 @@ export class LatLongField extends FormComponent {
86
66
  schema: {
87
67
  min: longitudeMin,
88
68
  max: longitudeMax,
89
- precision: DECIMAL_PRECISION,
90
- minPrecision: MIN_DECIMAL_PLACES,
91
- minLength: LONGITUDE_MIN_LENGTH,
92
- maxLength: LONGITUDE_MAX_LENGTH
69
+ precision: DECIMAL_PRECISION
93
70
  },
94
71
  options: {
95
72
  required: isRequired,
@@ -1 +1 @@
1
- {"version":3,"file":"LatLongField.js","names":["ComponentType","ComponentCollection","FormComponent","isFormState","createLocationFieldValidator","getLocationFieldViewModel","NumberField","messageTemplate","convertToLanguageMessages","DECIMAL_PRECISION","MIN_DECIMAL_PLACES","LATITUDE_MIN_LENGTH","LATITUDE_MAX_LENGTH","LONGITUDE_MIN_LENGTH","LONGITUDE_MAX_LENGTH","LatLongField","constructor","def","props","name","options","schema","isRequired","required","latitudeMin","latitude","min","latitudeMax","max","longitudeMin","longitude","longitudeMax","customValidationMessages","objectMissing","latitudeMessages","title","longitudeMessages","collection","type","precision","minPrecision","minLength","maxLength","optionalText","classes","suffix","parent","custom","getValidatorLatLong","peers","formSchema","stateSchema","getFormValueFromState","state","value","isLatLong","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber","component"],"sources":["../../../../../src/server/plugins/engine/components/LatLongField.ts"],"sourcesContent":["import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\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 createLocationFieldValidator,\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\nconst MIN_DECIMAL_PLACES = 1 // At least 1 decimal place required\n\n// Latitude length constraints\n// Min: 3 chars for values like \"52.1\" (2 digits + decimal + 1 decimal place)\n// Max: 10 chars for values like \"59.1234567\" (2 digits + decimal + 7 decimal places)\nconst LATITUDE_MIN_LENGTH = 3\nconst LATITUDE_MAX_LENGTH = 10\n\n// Longitude length constraints\n// Min: 2 chars for values like \"-1\" or single digit with decimal (needs min decimal places)\n// Max: 10 chars for values like \"-1.1234567\" (minus + 1 digit + decimal + 7 decimal places)\nconst LONGITUDE_MIN_LENGTH = 2\nconst LONGITUDE_MAX_LENGTH = 10\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\n const latitudeMax = schema?.latitude?.max ?? 60\n const longitudeMin = schema?.longitude?.min ?? -9\n const longitudeMax = schema?.longitude?.max ?? 2\n\n const customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\n 'number.precision':\n '{{#label}} must have no more than 7 decimal places',\n 'number.minPrecision':\n '{{#label}} must have at least {{#minPrecision}} decimal place',\n 'number.unsafe': '{{#label}} must be a valid number'\n })\n\n const latitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'number.base': `Enter a valid latitude for ${this.title} like 51.519450`,\n 'number.min': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`,\n 'number.max': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`,\n 'number.minLength': `Latitude for ${this.title} must be between 3 and 10 characters`,\n 'number.maxLength': `Latitude for ${this.title} must be between 3 and 10 characters`\n })\n\n const longitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'number.base': `Enter a valid longitude for ${this.title} like -0.127758`,\n 'number.min': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`,\n 'number.max': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`,\n 'number.minLength': `Longitude for ${this.title} must be between 2 and 10 characters`,\n 'number.maxLength': `Longitude for ${this.title} must be between 2 and 10 characters`\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 minPrecision: MIN_DECIMAL_PLACES,\n minLength: LATITUDE_MIN_LENGTH,\n maxLength: LATITUDE_MAX_LENGTH\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 minPrecision: MIN_DECIMAL_PLACES,\n minLength: LONGITUDE_MIN_LENGTH,\n maxLength: LONGITUDE_MAX_LENGTH\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 custom: getValidatorLatLong(this),\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: Lat: <<entry>>\\nLong: <<entry>>\n return `Lat: ${value.latitude}\\nLong: ${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 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:\n 'Enter a valid latitude for [short description] like 51.519450'\n },\n {\n type: 'longitudeFormat',\n template:\n 'Enter a valid longitude for [short description] like -0.127758'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'latitudeMin',\n template: 'Latitude for [short description] must be between 49 and 60'\n },\n {\n type: 'latitudeMax',\n template: 'Latitude for [short description] must be between 49 and 60'\n },\n {\n type: 'longitudeMin',\n template: 'Longitude for [short description] must be between -9 and 2'\n },\n {\n type: 'longitudeMax',\n template: 'Longitude for [short description] 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\nexport function getValidatorLatLong(component: LatLongField) {\n return createLocationFieldValidator(component)\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"LatLongField.js","names":["ComponentType","ComponentCollection","FormComponent","isFormState","createLocationFieldValidator","getLocationFieldViewModel","NumberField","messageTemplate","convertToLanguageMessages","DECIMAL_PRECISION","LatLongField","constructor","def","props","name","options","schema","isRequired","required","latitudeMin","latitude","min","latitudeMax","max","longitudeMin","longitude","longitudeMax","customValidationMessages","objectMissing","latitudeMessages","title","longitudeMessages","collection","type","precision","optionalText","classes","suffix","parent","custom","getValidatorLatLong","peers","formSchema","stateSchema","getFormValueFromState","state","value","isLatLong","undefined","getDisplayStringFromFormValue","getDisplayStringFromState","getContextValueFromFormValue","getContextValueFromState","getViewModel","payload","errors","viewModel","isState","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors","isNumber","component"],"sources":["../../../../../src/server/plugins/engine/components/LatLongField.ts"],"sourcesContent":["import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model'\nimport { type LanguageMessages, type ObjectSchema } from 'joi'\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 createLocationFieldValidator,\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 customValidationMessages: LanguageMessages =\n convertToLanguageMessages({\n 'any.required': messageTemplate.objectMissing,\n 'number.base': messageTemplate.objectMissing,\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 latitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'number.base': `Enter a valid latitude for ${this.title} like 51.519450`,\n 'number.min': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`,\n 'number.max': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`\n })\n\n const longitudeMessages: LanguageMessages = convertToLanguageMessages({\n ...customValidationMessages,\n 'number.base': `Enter a valid longitude for ${this.title} like -0.127758`,\n 'number.min': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`,\n 'number.max': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`\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 custom: getValidatorLatLong(this),\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: Lat: <<entry>>\\nLong: <<entry>>\n return `Lat: ${value.latitude}\\nLong: ${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 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:\n 'Enter a valid latitude for [short description] like 51.519450'\n },\n {\n type: 'longitudeFormat',\n template:\n 'Enter a valid longitude for [short description] like -0.127758'\n }\n ],\n advancedSettingsErrors: [\n {\n type: 'latitudeMin',\n template: 'Latitude for [short description] must be between 49 and 60'\n },\n {\n type: 'latitudeMax',\n template: 'Latitude for [short description] must be between 49 and 60'\n },\n {\n type: 'longitudeMin',\n template: 'Longitude for [short description] must be between -9 and 2'\n },\n {\n type: 'longitudeMax',\n template: 'Longitude for [short description] 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\nexport function getValidatorLatLong(component: LatLongField) {\n return createLocationFieldValidator(component)\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  import { type FormComponentsDef } from '@defra/forms-model';
2
- import joi, { type LanguageMessages, type StringSchema } from 'joi';
2
+ import { 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 {
@@ -12,8 +12,6 @@ interface LocationFieldOptions {
12
12
  interface ValidationConfig {
13
13
  pattern: RegExp;
14
14
  patternErrorMessage: string;
15
- customValidation?: (value: string, helpers: joi.CustomHelpers) => string | joi.ErrorReport;
16
- additionalMessages?: LanguageMessages;
17
15
  }
18
16
  /**
19
17
  * Abstract base class for location-based field components
@@ -18,21 +18,14 @@ export class LocationFieldBase extends FormComponent {
18
18
  addClassOptionIfNone(locationOptions, 'govuk-input--width-10');
19
19
  const config = this.getValidationConfig();
20
20
  let formSchema = joi.string().trim().label(this.label).required().pattern(config.pattern).messages({
21
- 'string.pattern.base': config.patternErrorMessage,
22
- ...config.additionalMessages
21
+ 'string.pattern.base': config.patternErrorMessage
23
22
  });
24
- if (config.customValidation) {
25
- formSchema = formSchema.custom(config.customValidation);
26
- }
27
23
  if (locationOptions.required === false) {
28
24
  formSchema = formSchema.allow('');
29
25
  }
30
26
  if (locationOptions.customValidationMessage) {
31
27
  const message = locationOptions.customValidationMessage;
32
28
  const messageKeys = ['any.required', 'string.empty', 'string.pattern.base'];
33
- if (config.additionalMessages) {
34
- messageKeys.push(...Object.keys(config.additionalMessages));
35
- }
36
29
  const messages = messageKeys.reduce((acc, key) => {
37
30
  acc[key] = message;
38
31
  return acc;
@@ -1 +1 @@
1
- {"version":3,"file":"LocationFieldBase.js","names":["joi","FormComponent","isFormValue","addClassOptionIfNone","markdown","messageTemplate","LocationFieldBase","instructionText","constructor","def","props","options","locationOptions","config","getValidationConfig","formSchema","string","trim","label","required","pattern","messages","patternErrorMessage","additionalMessages","customValidation","custom","allow","customValidationMessage","message","messageKeys","push","Object","keys","reduce","acc","key","customValidationMessages","default","stateSchema","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","isText","getViewModel","payload","errors","viewModel","parse","async","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, type StringSchema } 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 { markdown } from '~/src/server/plugins/engine/components/markdownParser.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'\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: string\n customValidation?: (\n value: string,\n helpers: joi.CustomHelpers\n ) => string | joi.ErrorReport\n additionalMessages?: LanguageMessages\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: string\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\n let formSchema = joi\n .string()\n .trim()\n .label(this.label)\n .required()\n .pattern(config.pattern)\n .messages({\n 'string.pattern.base': config.patternErrorMessage,\n ...config.additionalMessages\n })\n\n if (config.customValidation) {\n formSchema = formSchema.custom(config.customValidation)\n }\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 if (config.additionalMessages) {\n messageKeys.push(...Object.keys(config.additionalMessages))\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: markdown.parse(this.instructionText, { async: false })\n }\n }\n\n return viewModel\n }\n\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\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":[]}
1
+ {"version":3,"file":"LocationFieldBase.js","names":["joi","FormComponent","isFormValue","addClassOptionIfNone","markdown","messageTemplate","LocationFieldBase","instructionText","constructor","def","props","options","locationOptions","config","getValidationConfig","formSchema","string","trim","label","required","pattern","messages","patternErrorMessage","allow","customValidationMessage","message","messageKeys","reduce","acc","key","customValidationMessages","default","stateSchema","getFormValueFromState","state","name","getFormValue","value","isValue","undefined","isText","getViewModel","payload","errors","viewModel","parse","async","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, type StringSchema } 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 { markdown } from '~/src/server/plugins/engine/components/markdownParser.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'\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: string\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: string\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\n let formSchema = joi\n .string()\n .trim()\n .label(this.label)\n .required()\n .pattern(config.pattern)\n .messages({\n 'string.pattern.base': config.patternErrorMessage\n })\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: markdown.parse(this.instructionText, { async: false })\n }\n }\n\n return viewModel\n }\n\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\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":[]}
@@ -1,12 +1,10 @@
1
1
  import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model';
2
- import type joi from 'joi';
3
2
  import { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js';
4
3
  export declare class NationalGridFieldNumberField extends LocationFieldBase {
5
4
  options: NationalGridFieldNumberFieldComponent['options'];
6
5
  protected getValidationConfig(): {
7
6
  pattern: RegExp;
8
7
  patternErrorMessage: string;
9
- customValidation: (value: string, helpers: joi.CustomHelpers) => string | joi.ErrorReport;
10
8
  };
11
9
  protected getErrorTemplates(): {
12
10
  type: string;
@@ -1,25 +1,14 @@
1
1
  import { LocationFieldBase } from "./LocationFieldBase.js";
2
2
  export class NationalGridFieldNumberField extends LocationFieldBase {
3
3
  getValidationConfig() {
4
+ // Regex for OS grid references and parcel IDs
5
+ // Validates specific valid OS grid letter combinations with:
6
+ // - 2 letters & 8 digits in 2 blocks of 4 (parcel ID) e.g., ST 6789 6789
7
+ // - 2 letters & 10 digits in 2 blocks of 5 (OS grid reference) e.g., SO 12345 12345
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})|([0-9]{5})\s?([0-9]{5}))$/;
4
9
  return {
5
- // Pattern allows spaces and commas in the input since custom validation will clean them
6
- pattern: /^[A-Z]{2}[\d\s,]*$/i,
7
- patternErrorMessage: `Enter a valid National Grid field number for ${this.title} like NG 1234 5678`,
8
- customValidation: (value, helpers) => {
9
- // Strip spaces and commas for validation
10
- const cleanValue = value.replace(/[\s,]/g, '');
11
-
12
- // Check if it matches the exact pattern after cleaning
13
- if (!/^[A-Z]{2}\d{8}$/i.test(cleanValue)) {
14
- return helpers.error('string.pattern.base');
15
- }
16
-
17
- // Format with spaces per GDS guidance: NG 1234 5678
18
- const letters = cleanValue.substring(0, 2);
19
- const numbers = cleanValue.substring(2);
20
- const formattedValue = `${letters} ${numbers.substring(0, 4)} ${numbers.substring(4)}`;
21
- return formattedValue;
22
- }
10
+ pattern,
11
+ patternErrorMessage: `Enter a valid National Grid field number for ${this.title} like NG 1234 5678`
23
12
  };
24
13
  }
25
14
  getErrorTemplates() {
@@ -1 +1 @@
1
- {"version":3,"file":"NationalGridFieldNumberField.js","names":["LocationFieldBase","NationalGridFieldNumberField","getValidationConfig","pattern","patternErrorMessage","title","customValidation","value","helpers","cleanValue","replace","test","error","letters","substring","numbers","formattedValue","getErrorTemplates","type","template","getAllPossibleErrors","instance","Object","create","prototype"],"sources":["../../../../../src/server/plugins/engine/components/NationalGridFieldNumberField.ts"],"sourcesContent":["import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model'\nimport type joi from 'joi'\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 return {\n // Pattern allows spaces and commas in the input since custom validation will clean them\n pattern: /^[A-Z]{2}[\\d\\s,]*$/i,\n patternErrorMessage: `Enter a valid National Grid field number for ${this.title} like NG 1234 5678`,\n customValidation: (value: string, helpers: joi.CustomHelpers) => {\n // Strip spaces and commas for validation\n const cleanValue = value.replace(/[\\s,]/g, '')\n\n // Check if it matches the exact pattern after cleaning\n if (!/^[A-Z]{2}\\d{8}$/i.test(cleanValue)) {\n return helpers.error('string.pattern.base')\n }\n\n // Format with spaces per GDS guidance: NG 1234 5678\n const letters = cleanValue.substring(0, 2)\n const numbers = cleanValue.substring(2)\n const formattedValue = `${letters} ${numbers.substring(0, 4)} ${numbers.substring(4)}`\n\n return formattedValue\n }\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template:\n 'Enter a valid National Grid field number for [short description] like NG 1234 5678'\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":"AAGA,SAASA,iBAAiB;AAE1B,OAAO,MAAMC,4BAA4B,SAASD,iBAAiB,CAAC;EAGxDE,mBAAmBA,CAAA,EAAG;IAC9B,OAAO;MACL;MACAC,OAAO,EAAE,qBAAqB;MAC9BC,mBAAmB,EAAE,gDAAgD,IAAI,CAACC,KAAK,oBAAoB;MACnGC,gBAAgB,EAAEA,CAACC,KAAa,EAAEC,OAA0B,KAAK;QAC/D;QACA,MAAMC,UAAU,GAAGF,KAAK,CAACG,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;;QAE9C;QACA,IAAI,CAAC,kBAAkB,CAACC,IAAI,CAACF,UAAU,CAAC,EAAE;UACxC,OAAOD,OAAO,CAACI,KAAK,CAAC,qBAAqB,CAAC;QAC7C;;QAEA;QACA,MAAMC,OAAO,GAAGJ,UAAU,CAACK,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAMC,OAAO,GAAGN,UAAU,CAACK,SAAS,CAAC,CAAC,CAAC;QACvC,MAAME,cAAc,GAAG,GAAGH,OAAO,IAAIE,OAAO,CAACD,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAIC,OAAO,CAACD,SAAS,CAAC,CAAC,CAAC,EAAE;QAEtF,OAAOE,cAAc;MACvB;IACF,CAAC;EACH;EAEUC,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EACN;IACJ,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOC,oBAAoBA,CAAA,EAAG;IAC5B,MAAMC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAC5BtB,4BAA4B,CAACuB,SAC/B,CAAiC;IACjC,OAAOH,QAAQ,CAACD,oBAAoB,CAAC,CAAC;EACxC;AACF","ignoreList":[]}
1
+ {"version":3,"file":"NationalGridFieldNumberField.js","names":["LocationFieldBase","NationalGridFieldNumberField","getValidationConfig","pattern","patternErrorMessage","title","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 grid references and parcel IDs\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 8 digits in 2 blocks of 4 (parcel ID) e.g., ST 6789 6789\n // - 2 letters & 10 digits in 2 blocks of 5 (OS grid reference) e.g., SO 12345 12345\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})|([0-9]{5})\\s?([0-9]{5}))$/\n\n return {\n pattern,\n patternErrorMessage: `Enter a valid National Grid field number for ${this.title} like NG 1234 5678`\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template:\n 'Enter a valid National Grid field number for [short description] like NG 1234 5678'\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;AAE1B,OAAO,MAAMC,4BAA4B,SAASD,iBAAiB,CAAC;EAGxDE,mBAAmBA,CAAA,EAAG;IAC9B;IACA;IACA;IACA;IACA,MAAMC,OAAO,GACX,6JAA6J;IAE/J,OAAO;MACLA,OAAO;MACPC,mBAAmB,EAAE,gDAAgD,IAAI,CAACC,KAAK;IACjF,CAAC;EACH;EAEUC,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EACN;IACJ,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOC,oBAAoBA,CAAA,EAAG;IAC5B,MAAMC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAC5BX,4BAA4B,CAACY,SAC/B,CAAiC;IACjC,OAAOH,QAAQ,CAACD,oBAAoB,CAAC,CAAC;EACxC;AACF","ignoreList":[]}
@@ -69,22 +69,4 @@ export declare class NumberField extends FormComponent {
69
69
  static getAllPossibleErrors(): ErrorMessageTemplateList;
70
70
  static isNumber(value?: FormStateValue | FormState): value is number;
71
71
  }
72
- /**
73
- * Validates string length of a numeric value
74
- * @param value - The numeric value to validate
75
- * @param minLength - Minimum required string length
76
- * @param maxLength - Maximum allowed string length
77
- * @returns Object with validation result
78
- */
79
- export declare function validateStringLength(value: number, minLength?: number, maxLength?: number): {
80
- isValid: boolean;
81
- error?: 'minLength' | 'maxLength';
82
- };
83
- /**
84
- * Validates minimum decimal precision
85
- * @param value - The numeric value to validate
86
- * @param minPrecision - Minimum required decimal places
87
- * @returns true if valid, false if invalid
88
- */
89
- export declare function validateMinimumPrecision(value: number, minPrecision: number): boolean;
90
72
  export declare function getValidatorPrecision(component: NumberField): joi.CustomValidator;
@@ -134,84 +134,6 @@ export class NumberField extends FormComponent {
134
134
  return typeof value === 'number';
135
135
  }
136
136
  }
137
-
138
- /**
139
- * Validates string length of a numeric value
140
- * @param value - The numeric value to validate
141
- * @param minLength - Minimum required string length
142
- * @param maxLength - Maximum allowed string length
143
- * @returns Object with validation result
144
- */
145
- export function validateStringLength(value, minLength, maxLength) {
146
- if (typeof minLength !== 'number' && typeof maxLength !== 'number') {
147
- return {
148
- isValid: true
149
- };
150
- }
151
- const valueStr = String(value);
152
- if (typeof minLength === 'number' && valueStr.length < minLength) {
153
- return {
154
- isValid: false,
155
- error: 'minLength'
156
- };
157
- }
158
- if (typeof maxLength === 'number' && valueStr.length > maxLength) {
159
- return {
160
- isValid: false,
161
- error: 'maxLength'
162
- };
163
- }
164
- return {
165
- isValid: true
166
- };
167
- }
168
-
169
- /**
170
- * Validates minimum decimal precision
171
- * @param value - The numeric value to validate
172
- * @param minPrecision - Minimum required decimal places
173
- * @returns true if valid, false if invalid
174
- */
175
- export function validateMinimumPrecision(value, minPrecision) {
176
- if (Number.isInteger(value)) {
177
- return false;
178
- }
179
- const valueStr = String(value);
180
- const decimalIndex = valueStr.indexOf('.');
181
- if (decimalIndex !== -1) {
182
- const decimalPlaces = valueStr.length - decimalIndex - 1;
183
- return decimalPlaces >= minPrecision;
184
- }
185
- return false;
186
- }
187
-
188
- /**
189
- * Helper function to handle length validation errors
190
- * Returns the appropriate error response based on the validation result
191
- */
192
- function handleLengthValidationError(lengthCheck, helpers, custom, minLength, maxLength) {
193
- if (!lengthCheck.isValid && lengthCheck.error) {
194
- const errorType = `number.${lengthCheck.error}`;
195
- if (custom) {
196
- // Only pass the relevant length value in context
197
- const contextData = lengthCheck.error === 'minLength' ? {
198
- minLength: minLength ?? 0
199
- } : {
200
- maxLength: maxLength ?? 0
201
- };
202
- return helpers.message({
203
- custom
204
- }, contextData);
205
- }
206
- const context = lengthCheck.error === 'minLength' ? {
207
- minLength: minLength ?? 0
208
- } : {
209
- maxLength: maxLength ?? 0
210
- };
211
- return helpers.error(errorType, context);
212
- }
213
- return null;
214
- }
215
137
  export function getValidatorPrecision(component) {
216
138
  const validator = (value, helpers) => {
217
139
  const {
@@ -222,24 +144,16 @@ export function getValidatorPrecision(component) {
222
144
  customValidationMessage: custom
223
145
  } = options;
224
146
  const {
225
- precision: limit,
226
- minPrecision,
227
- minLength,
228
- maxLength
147
+ precision: limit
229
148
  } = schema;
230
149
  if (!limit || limit <= 0) {
231
- const lengthCheck = validateStringLength(value, minLength, maxLength);
232
- const error = handleLengthValidationError(lengthCheck, helpers, custom, minLength, maxLength);
233
- if (error) return error;
234
150
  return value;
235
151
  }
236
-
237
- // Validate precision (max decimal places)
238
152
  const validationSchema = joi.number().precision(limit).prefs({
239
153
  convert: false
240
154
  });
241
155
  try {
242
- joi.attempt(value, validationSchema);
156
+ return joi.attempt(value, validationSchema);
243
157
  } catch {
244
158
  return custom ? helpers.message({
245
159
  custom
@@ -249,21 +163,6 @@ export function getValidatorPrecision(component) {
249
163
  limit
250
164
  });
251
165
  }
252
-
253
- // Validate minimum precision (min decimal places)
254
- if (typeof minPrecision === 'number' && minPrecision > 0) {
255
- if (!validateMinimumPrecision(value, minPrecision)) {
256
- return helpers.error('number.minPrecision', {
257
- minPrecision
258
- });
259
- }
260
- }
261
-
262
- // Check string length validation after precision checks
263
- const lengthCheck = validateStringLength(value, minLength, maxLength);
264
- const error = handleLengthValidationError(lengthCheck, helpers, custom, minLength, maxLength);
265
- if (error) return error;
266
- return value;
267
166
  };
268
167
  return validator;
269
168
  }