@defra/forms-engine-plugin 4.14.2 → 4.14.4

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.
@@ -1,15 +1,19 @@
1
- import joi from 'joi';
2
1
  import { FormComponent } from "./FormComponent.js";
3
2
  import { addClassOptionIfNone } from "./helpers/index.js";
3
+ import { INVALID_ERROR_CODE, joi } from "./helpers/telephone.js";
4
4
  import { messageTemplate } from "../pageControllers/validationOptions.js";
5
- const PATTERN = /^[0-9\\\s+()-]*$/;
6
5
  export class TelephoneNumberField extends FormComponent {
7
6
  constructor(def, props) {
8
7
  super(def, props);
9
8
  const {
10
9
  options
11
10
  } = def;
12
- let formSchema = joi.string().trim().pattern(PATTERN).label(this.label).required();
11
+ const {
12
+ format
13
+ } = options;
14
+ let formSchema = joi.string().trim().phoneNumber({
15
+ format
16
+ }).label(this.label).required();
13
17
  if (options.required === false) {
14
18
  formSchema = formSchema.allow('');
15
19
  }
@@ -18,7 +22,8 @@ export class TelephoneNumberField extends FormComponent {
18
22
  formSchema = formSchema.messages({
19
23
  'any.required': message,
20
24
  'string.empty': message,
21
- 'string.pattern.base': message
25
+ 'string.pattern.base': message,
26
+ [INVALID_ERROR_CODE]: message
22
27
  });
23
28
  } else if (options.customValidationMessages) {
24
29
  formSchema = formSchema.messages(options.customValidationMessages);
@@ -1 +1 @@
1
- {"version":3,"file":"TelephoneNumberField.js","names":["joi","FormComponent","addClassOptionIfNone","messageTemplate","PATTERN","TelephoneNumberField","constructor","def","props","options","formSchema","string","trim","pattern","label","required","allow","customValidationMessage","message","messages","customValidationMessages","default","stateSchema","getViewModel","payload","errors","viewModel","attributes","autocomplete","type","getAllPossibleErrors","baseErrors","template","format","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/TelephoneNumberField.ts"],"sourcesContent":["import { type TelephoneNumberFieldComponent } from '@defra/forms-model'\nimport joi, { type StringSchema } from 'joi'\n\nimport { FormComponent } 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 FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nconst PATTERN = /^[0-9\\\\\\s+()-]*$/\n\nexport class TelephoneNumberField extends FormComponent {\n declare options: TelephoneNumberFieldComponent['options']\n declare formSchema: StringSchema\n declare stateSchema: StringSchema\n\n constructor(\n def: TelephoneNumberFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options } = def\n\n let formSchema = joi\n .string()\n .trim()\n .pattern(PATTERN)\n .label(this.label)\n .required()\n\n if (options.required === false) {\n formSchema = formSchema.allow('')\n }\n\n if (options.customValidationMessage) {\n const message = options.customValidationMessage\n\n formSchema = formSchema.messages({\n 'any.required': message,\n 'string.empty': message,\n 'string.pattern.base': message\n })\n } else if (options.customValidationMessages) {\n formSchema = formSchema.messages(options.customValidationMessages)\n }\n\n addClassOptionIfNone(options, 'govuk-input--width-20')\n\n this.formSchema = formSchema.default('')\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = options\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n const { attributes } = viewModel\n\n attributes.autocomplete = 'tel'\n\n return {\n ...viewModel,\n type: 'tel'\n }\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return TelephoneNumberField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\n { type: 'format', template: messageTemplate.format }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AACA,OAAOA,GAAG,MAA6B,KAAK;AAE5C,SAASC,aAAa;AACtB,SAASC,oBAAoB;AAC7B,SAASC,eAAe;AAOxB,MAAMC,OAAO,GAAG,kBAAkB;AAElC,OAAO,MAAMC,oBAAoB,SAASJ,aAAa,CAAC;EAKtDK,WAAWA,CACTC,GAAkC,EAClCC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEC;IAAQ,CAAC,GAAGF,GAAG;IAEvB,IAAIG,UAAU,GAAGV,GAAG,CACjBW,MAAM,CAAC,CAAC,CACRC,IAAI,CAAC,CAAC,CACNC,OAAO,CAACT,OAAO,CAAC,CAChBU,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC,CACjBC,QAAQ,CAAC,CAAC;IAEb,IAAIN,OAAO,CAACM,QAAQ,KAAK,KAAK,EAAE;MAC9BL,UAAU,GAAGA,UAAU,CAACM,KAAK,CAAC,EAAE,CAAC;IACnC;IAEA,IAAIP,OAAO,CAACQ,uBAAuB,EAAE;MACnC,MAAMC,OAAO,GAAGT,OAAO,CAACQ,uBAAuB;MAE/CP,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAAC;QAC/B,cAAc,EAAED,OAAO;QACvB,cAAc,EAAEA,OAAO;QACvB,qBAAqB,EAAEA;MACzB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAIT,OAAO,CAACW,wBAAwB,EAAE;MAC3CV,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAACV,OAAO,CAACW,wBAAwB,CAAC;IACpE;IAEAlB,oBAAoB,CAACO,OAAO,EAAE,uBAAuB,CAAC;IAEtD,IAAI,CAACC,UAAU,GAAGA,UAAU,CAACW,OAAO,CAAC,EAAE,CAAC;IACxC,IAAI,CAACC,WAAW,GAAGZ,UAAU,CAACW,OAAO,CAAC,IAAI,CAAC,CAACL,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,CAACP,OAAO,GAAGA,OAAO;EACxB;EAEAc,YAAYA,CAACC,OAAoB,EAAEC,MAA8B,EAAE;IACjE,MAAMC,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,EAAEC,MAAM,CAAC;IACrD,MAAM;MAAEE;IAAW,CAAC,GAAGD,SAAS;IAEhCC,UAAU,CAACC,YAAY,GAAG,KAAK;IAE/B,OAAO;MACL,GAAGF,SAAS;MACZG,IAAI,EAAE;IACR,CAAC;EACH;;EAEA;AACF;AACA;EACEC,oBAAoBA,CAAA,EAA6B;IAC/C,OAAOzB,oBAAoB,CAACyB,oBAAoB,CAAC,CAAC;EACpD;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QAAEF,IAAI,EAAE,UAAU;QAAEG,QAAQ,EAAE7B,eAAe,CAACY;MAAS,CAAC,EACxD;QAAEc,IAAI,EAAE,QAAQ;QAAEG,QAAQ,EAAE7B,eAAe,CAAC8B;MAAO,CAAC,CACrD;MACDC,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
1
+ {"version":3,"file":"TelephoneNumberField.js","names":["FormComponent","addClassOptionIfNone","INVALID_ERROR_CODE","joi","messageTemplate","TelephoneNumberField","constructor","def","props","options","format","formSchema","string","trim","phoneNumber","label","required","allow","customValidationMessage","message","messages","customValidationMessages","default","stateSchema","getViewModel","payload","errors","viewModel","attributes","autocomplete","type","getAllPossibleErrors","baseErrors","template","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/TelephoneNumberField.ts"],"sourcesContent":["import { type TelephoneNumberFieldComponent } from '@defra/forms-model'\nimport { type StringSchema } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { addClassOptionIfNone } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport {\n INVALID_ERROR_CODE,\n joi\n} from '~/src/server/plugins/engine/components/helpers/telephone.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormSubmissionError\n} from '~/src/server/plugins/engine/types.js'\n\nexport class TelephoneNumberField extends FormComponent {\n declare options: TelephoneNumberFieldComponent['options']\n declare formSchema: StringSchema\n declare stateSchema: StringSchema\n\n constructor(\n def: TelephoneNumberFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { options } = def\n const { format } = options\n\n let formSchema = joi\n .string()\n .trim()\n .phoneNumber({ format })\n .label(this.label)\n .required()\n\n if (options.required === false) {\n formSchema = formSchema.allow('')\n }\n\n if (options.customValidationMessage) {\n const message = options.customValidationMessage\n\n formSchema = formSchema.messages({\n 'any.required': message,\n 'string.empty': message,\n 'string.pattern.base': message,\n [INVALID_ERROR_CODE]: message\n })\n } else if (options.customValidationMessages) {\n formSchema = formSchema.messages(options.customValidationMessages)\n }\n\n addClassOptionIfNone(options, 'govuk-input--width-20')\n\n this.formSchema = formSchema.default('')\n this.stateSchema = formSchema.default(null).allow(null)\n this.options = options\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n const { attributes } = viewModel\n\n attributes.autocomplete = 'tel'\n\n return {\n ...viewModel,\n type: 'tel'\n }\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return TelephoneNumberField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: messageTemplate.required },\n { type: 'format', template: messageTemplate.format }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AAGA,SAASA,aAAa;AACtB,SAASC,oBAAoB;AAC7B,SACEC,kBAAkB,EAClBC,GAAG;AAEL,SAASC,eAAe;AAOxB,OAAO,MAAMC,oBAAoB,SAASL,aAAa,CAAC;EAKtDM,WAAWA,CACTC,GAAkC,EAClCC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAM;MAAEC;IAAQ,CAAC,GAAGF,GAAG;IACvB,MAAM;MAAEG;IAAO,CAAC,GAAGD,OAAO;IAE1B,IAAIE,UAAU,GAAGR,GAAG,CACjBS,MAAM,CAAC,CAAC,CACRC,IAAI,CAAC,CAAC,CACNC,WAAW,CAAC;MAAEJ;IAAO,CAAC,CAAC,CACvBK,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC,CACjBC,QAAQ,CAAC,CAAC;IAEb,IAAIP,OAAO,CAACO,QAAQ,KAAK,KAAK,EAAE;MAC9BL,UAAU,GAAGA,UAAU,CAACM,KAAK,CAAC,EAAE,CAAC;IACnC;IAEA,IAAIR,OAAO,CAACS,uBAAuB,EAAE;MACnC,MAAMC,OAAO,GAAGV,OAAO,CAACS,uBAAuB;MAE/CP,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAAC;QAC/B,cAAc,EAAED,OAAO;QACvB,cAAc,EAAEA,OAAO;QACvB,qBAAqB,EAAEA,OAAO;QAC9B,CAACjB,kBAAkB,GAAGiB;MACxB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAIV,OAAO,CAACY,wBAAwB,EAAE;MAC3CV,UAAU,GAAGA,UAAU,CAACS,QAAQ,CAACX,OAAO,CAACY,wBAAwB,CAAC;IACpE;IAEApB,oBAAoB,CAACQ,OAAO,EAAE,uBAAuB,CAAC;IAEtD,IAAI,CAACE,UAAU,GAAGA,UAAU,CAACW,OAAO,CAAC,EAAE,CAAC;IACxC,IAAI,CAACC,WAAW,GAAGZ,UAAU,CAACW,OAAO,CAAC,IAAI,CAAC,CAACL,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,CAACR,OAAO,GAAGA,OAAO;EACxB;EAEAe,YAAYA,CAACC,OAAoB,EAAEC,MAA8B,EAAE;IACjE,MAAMC,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,EAAEC,MAAM,CAAC;IACrD,MAAM;MAAEE;IAAW,CAAC,GAAGD,SAAS;IAEhCC,UAAU,CAACC,YAAY,GAAG,KAAK;IAE/B,OAAO;MACL,GAAGF,SAAS;MACZG,IAAI,EAAE;IACR,CAAC;EACH;;EAEA;AACF;AACA;EACEC,oBAAoBA,CAAA,EAA6B;IAC/C,OAAO1B,oBAAoB,CAAC0B,oBAAoB,CAAC,CAAC;EACpD;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QAAEF,IAAI,EAAE,UAAU;QAAEG,QAAQ,EAAE7B,eAAe,CAACY;MAAS,CAAC,EACxD;QAAEc,IAAI,EAAE,QAAQ;QAAEG,QAAQ,EAAE7B,eAAe,CAACM;MAAO,CAAC,CACrD;MACDwB,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
@@ -2,6 +2,3 @@ import { type GeospatialFieldComponent } from '@defra/forms-model';
2
2
  import JoiBase from 'joi';
3
3
  import { type Feature } from '../../../../../server/plugins/engine/types.js';
4
4
  export declare function getGeospatialSchema(def: GeospatialFieldComponent): JoiBase.ArraySchema<Feature[]>;
5
- /**
6
- * @import { CustomHelpers } from 'joi'
7
- */
@@ -122,8 +122,4 @@ export function getGeospatialSchema(def) {
122
122
  };
123
123
  return applySchemaConstraints(Joi.array().items(featureSchema.custom(validateCountryBounds)).unique('id'), def);
124
124
  }
125
-
126
- /**
127
- * @import { CustomHelpers } from 'joi'
128
- */
129
125
  //# sourceMappingURL=geospatial.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"geospatial.js","names":["GeospatialFieldOptionsCountryEnum","Bourne","booleanWithin","JoiBase","countries","countriesDesc","England","NorthernIreland","Scotland","Wales","Joi","extend","type","base","array","messages","coerce","from","method","value","helpers","trimmed","trim","undefined","parse","result","errors","error","coordinatesSchema","items","number","required","featurePropertiesSchema","object","keys","description","string","coordinateGridReference","centroidGridReference","featureGeometrySchema","valid","coordinates","when","switch","is","then","min","featureSchema","id","properties","geometry","applySchemaConstraints","schema","def","options","constraints","isOptional","length","max","optional","getGeospatialSchema","country","at","unique","validateCountryBounds","countryFeature","features","find","feature","custom"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/geospatial.ts"],"sourcesContent":["import {\n GeospatialFieldOptionsCountryEnum,\n type GeospatialFieldComponent,\n type GeospatialFieldOptionsCountry\n} from '@defra/forms-model'\nimport Bourne from '@hapi/bourne'\nimport { booleanWithin } from '@turf/boolean-within'\nimport JoiBase, { type CustomValidator } from 'joi'\n\nimport {\n type Coordinates,\n type Feature,\n type FeatureProperties,\n type Geometry\n} from '~/src/server/plugins/engine/types.js'\nimport { countries } from '~/src/server/plugins/map/routes/index.js'\n\nconst countriesDesc: Record<GeospatialFieldOptionsCountryEnum, string> = {\n [GeospatialFieldOptionsCountryEnum.England]: 'England',\n [GeospatialFieldOptionsCountryEnum.NorthernIreland]: 'Northern Ireland',\n [GeospatialFieldOptionsCountryEnum.Scotland]: 'Scotland',\n [GeospatialFieldOptionsCountryEnum.Wales]: 'Wales'\n}\n\nconst Joi = JoiBase.extend({\n type: 'array',\n base: JoiBase.array(),\n messages: {\n 'object.invalidjson': '{{#label}} must be a valid json array string'\n },\n coerce: {\n from: 'string',\n method(value, helpers) {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed === '' || trimmed === '[]') {\n return {\n value: undefined\n }\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n return { value: Bourne.parse(value) }\n } catch {\n const result = {\n value,\n errors: [helpers.error('object.invalidjson')]\n }\n\n return result\n }\n } else {\n return {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n value\n }\n }\n }\n }\n}) as JoiBase.Root\n\nconst coordinatesSchema = Joi.array<Coordinates[]>()\n .items(Joi.number().required(), Joi.number().required())\n .required()\n\nconst featurePropertiesSchema = Joi.object<FeatureProperties>()\n .keys({\n description: Joi.string().required(),\n coordinateGridReference: Joi.string().required(),\n centroidGridReference: Joi.string().required()\n })\n .required()\n\nconst featureGeometrySchema = Joi.object<Geometry>().keys({\n type: Joi.string().valid('Point', 'LineString', 'Polygon').required(),\n coordinates: Joi.array()\n .when('type', {\n switch: [\n { is: 'Point', then: coordinatesSchema },\n {\n is: 'LineString',\n then: Joi.array().items(coordinatesSchema).min(2)\n },\n {\n is: 'Polygon',\n then: Joi.array().items(Joi.array().items(coordinatesSchema).min(3))\n }\n ]\n })\n .required()\n})\n\nconst featureSchema = Joi.object<Feature>().keys({\n id: Joi.string().required(),\n type: Joi.string().valid('Feature').required(),\n properties: featurePropertiesSchema,\n geometry: featureGeometrySchema\n})\n\nfunction applySchemaConstraints(\n schema: JoiBase.ArraySchema<Feature[]>,\n def: GeospatialFieldComponent\n) {\n const { options, schema: constraints } = def\n const isOptional = options.required === false\n\n if (typeof constraints?.length === 'number') {\n schema = schema.length(constraints.length)\n } else {\n if (typeof constraints?.min === 'number') {\n schema = schema.min(constraints.min)\n } else if (!isOptional) {\n schema = schema.min(1)\n }\n\n schema = schema.max(\n typeof constraints?.max === 'number' ? constraints.max : 50\n )\n }\n\n if (isOptional) {\n schema = schema.optional()\n } else {\n schema = schema.required()\n }\n\n return schema\n}\n\nexport function getGeospatialSchema(\n def: GeospatialFieldComponent\n): JoiBase.ArraySchema<Feature[]> {\n const { options = {} } = def\n const country: GeospatialFieldOptionsCountry | undefined =\n options.countries?.at(0)\n\n if (!country) {\n return applySchemaConstraints(\n Joi.array<Feature[]>().items(featureSchema).unique('id'),\n def\n )\n }\n\n const validateCountryBounds: CustomValidator = (value, helpers) => {\n const countryFeature = countries.features.find(\n (feature) => feature.id === country\n )\n\n if (!countryFeature) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value\n }\n\n const result = booleanWithin(value as Geometry | Feature, countryFeature)\n\n if (!result) {\n return helpers.error('any.custom', {\n country: countriesDesc[country as GeospatialFieldOptionsCountryEnum]\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value\n }\n\n return applySchemaConstraints(\n Joi.array<Feature[]>()\n .items(featureSchema.custom(validateCountryBounds))\n .unique('id'),\n def\n )\n}\n\n/**\n * @import { CustomHelpers } from 'joi'\n */\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"geospatial.js","names":["GeospatialFieldOptionsCountryEnum","Bourne","booleanWithin","JoiBase","countries","countriesDesc","England","NorthernIreland","Scotland","Wales","Joi","extend","type","base","array","messages","coerce","from","method","value","helpers","trimmed","trim","undefined","parse","result","errors","error","coordinatesSchema","items","number","required","featurePropertiesSchema","object","keys","description","string","coordinateGridReference","centroidGridReference","featureGeometrySchema","valid","coordinates","when","switch","is","then","min","featureSchema","id","properties","geometry","applySchemaConstraints","schema","def","options","constraints","isOptional","length","max","optional","getGeospatialSchema","country","at","unique","validateCountryBounds","countryFeature","features","find","feature","custom"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/geospatial.ts"],"sourcesContent":["import {\n GeospatialFieldOptionsCountryEnum,\n type GeospatialFieldComponent,\n type GeospatialFieldOptionsCountry\n} from '@defra/forms-model'\nimport Bourne from '@hapi/bourne'\nimport { booleanWithin } from '@turf/boolean-within'\nimport JoiBase, { type CustomValidator } from 'joi'\n\nimport {\n type Coordinates,\n type Feature,\n type FeatureProperties,\n type Geometry\n} from '~/src/server/plugins/engine/types.js'\nimport { countries } from '~/src/server/plugins/map/routes/index.js'\n\nconst countriesDesc: Record<GeospatialFieldOptionsCountryEnum, string> = {\n [GeospatialFieldOptionsCountryEnum.England]: 'England',\n [GeospatialFieldOptionsCountryEnum.NorthernIreland]: 'Northern Ireland',\n [GeospatialFieldOptionsCountryEnum.Scotland]: 'Scotland',\n [GeospatialFieldOptionsCountryEnum.Wales]: 'Wales'\n}\n\nconst Joi = JoiBase.extend({\n type: 'array',\n base: JoiBase.array(),\n messages: {\n 'object.invalidjson': '{{#label}} must be a valid json array string'\n },\n coerce: {\n from: 'string',\n method(value, helpers) {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed === '' || trimmed === '[]') {\n return {\n value: undefined\n }\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n return { value: Bourne.parse(value) }\n } catch {\n const result = {\n value,\n errors: [helpers.error('object.invalidjson')]\n }\n\n return result\n }\n } else {\n return {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n value\n }\n }\n }\n }\n}) as JoiBase.Root\n\nconst coordinatesSchema = Joi.array<Coordinates[]>()\n .items(Joi.number().required(), Joi.number().required())\n .required()\n\nconst featurePropertiesSchema = Joi.object<FeatureProperties>()\n .keys({\n description: Joi.string().required(),\n coordinateGridReference: Joi.string().required(),\n centroidGridReference: Joi.string().required()\n })\n .required()\n\nconst featureGeometrySchema = Joi.object<Geometry>().keys({\n type: Joi.string().valid('Point', 'LineString', 'Polygon').required(),\n coordinates: Joi.array()\n .when('type', {\n switch: [\n { is: 'Point', then: coordinatesSchema },\n {\n is: 'LineString',\n then: Joi.array().items(coordinatesSchema).min(2)\n },\n {\n is: 'Polygon',\n then: Joi.array().items(Joi.array().items(coordinatesSchema).min(3))\n }\n ]\n })\n .required()\n})\n\nconst featureSchema = Joi.object<Feature>().keys({\n id: Joi.string().required(),\n type: Joi.string().valid('Feature').required(),\n properties: featurePropertiesSchema,\n geometry: featureGeometrySchema\n})\n\nfunction applySchemaConstraints(\n schema: JoiBase.ArraySchema<Feature[]>,\n def: GeospatialFieldComponent\n) {\n const { options, schema: constraints } = def\n const isOptional = options.required === false\n\n if (typeof constraints?.length === 'number') {\n schema = schema.length(constraints.length)\n } else {\n if (typeof constraints?.min === 'number') {\n schema = schema.min(constraints.min)\n } else if (!isOptional) {\n schema = schema.min(1)\n }\n\n schema = schema.max(\n typeof constraints?.max === 'number' ? constraints.max : 50\n )\n }\n\n if (isOptional) {\n schema = schema.optional()\n } else {\n schema = schema.required()\n }\n\n return schema\n}\n\nexport function getGeospatialSchema(\n def: GeospatialFieldComponent\n): JoiBase.ArraySchema<Feature[]> {\n const { options = {} } = def\n const country: GeospatialFieldOptionsCountry | undefined =\n options.countries?.at(0)\n\n if (!country) {\n return applySchemaConstraints(\n Joi.array<Feature[]>().items(featureSchema).unique('id'),\n def\n )\n }\n\n const validateCountryBounds: CustomValidator = (value, helpers) => {\n const countryFeature = countries.features.find(\n (feature) => feature.id === country\n )\n\n if (!countryFeature) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value\n }\n\n const result = booleanWithin(value as Geometry | Feature, countryFeature)\n\n if (!result) {\n return helpers.error('any.custom', {\n country: countriesDesc[country as GeospatialFieldOptionsCountryEnum]\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value\n }\n\n return applySchemaConstraints(\n Joi.array<Feature[]>()\n .items(featureSchema.custom(validateCountryBounds))\n .unique('id'),\n def\n )\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ import LibPhoneNumber from 'google-libphonenumber';
2
+ import JoiBase from 'joi';
3
+ export declare const COUNTRY = "GB";
4
+ export declare const INVALID_ERROR_CODE = "phoneNumber.invalid";
5
+ export declare const isUKNumber: (value: LibPhoneNumber.PhoneNumber) => boolean;
6
+ export declare const joi: JoiBase.Root;
@@ -0,0 +1,57 @@
1
+ import { TelephoneNumberFieldOptionsFormatEnum } from '@defra/forms-model';
2
+ import LibPhoneNumber from 'google-libphonenumber';
3
+ import JoiBase from 'joi';
4
+ import { messageTemplate } from "../../pageControllers/validationOptions.js";
5
+ const phoneUtil = LibPhoneNumber.PhoneNumberUtil.getInstance();
6
+ export const COUNTRY = 'GB';
7
+ export const INVALID_ERROR_CODE = 'phoneNumber.invalid';
8
+ export const isUKNumber = value => {
9
+ return phoneUtil.isValidNumberForRegion(value, COUNTRY);
10
+ };
11
+ export const joi = JoiBase.extend({
12
+ type: 'string',
13
+ base: JoiBase.string(),
14
+ messages: {
15
+ [INVALID_ERROR_CODE]: messageTemplate.format
16
+ },
17
+ rules: {
18
+ phoneNumber: {
19
+ method({
20
+ format
21
+ } = {}) {
22
+ return this.$_addRule({
23
+ name: 'phoneNumber',
24
+ args: {
25
+ format
26
+ }
27
+ });
28
+ },
29
+ args: [{
30
+ name: 'format',
31
+ ref: true,
32
+ assert: JoiBase.valid(TelephoneNumberFieldOptionsFormatEnum.International, TelephoneNumberFieldOptionsFormatEnum.UK)
33
+ }],
34
+ validate(value, {
35
+ error
36
+ }, args) {
37
+ const format = args.format;
38
+ try {
39
+ const parsed = phoneUtil.parse(value, COUNTRY);
40
+ if (!phoneUtil.isValidNumber(parsed)) {
41
+ return error(INVALID_ERROR_CODE);
42
+ }
43
+ if (format) {
44
+ const isUK = isUKNumber(parsed);
45
+ if (!isUK && format === TelephoneNumberFieldOptionsFormatEnum.UK || isUK && format === TelephoneNumberFieldOptionsFormatEnum.International) {
46
+ return error(INVALID_ERROR_CODE);
47
+ }
48
+ }
49
+ return value;
50
+ } catch {
51
+ return error(INVALID_ERROR_CODE);
52
+ }
53
+ }
54
+ }
55
+ }
56
+ });
57
+ //# sourceMappingURL=telephone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telephone.js","names":["TelephoneNumberFieldOptionsFormatEnum","LibPhoneNumber","JoiBase","messageTemplate","phoneUtil","PhoneNumberUtil","getInstance","COUNTRY","INVALID_ERROR_CODE","isUKNumber","value","isValidNumberForRegion","joi","extend","type","base","string","messages","format","rules","phoneNumber","method","$_addRule","name","args","ref","assert","valid","International","UK","validate","error","parsed","parse","isValidNumber","isUK"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/telephone.ts"],"sourcesContent":["import { TelephoneNumberFieldOptionsFormatEnum } from '@defra/forms-model'\nimport LibPhoneNumber from 'google-libphonenumber'\nimport JoiBase, { type LanguageMessages } from 'joi'\n\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\n\nconst phoneUtil = LibPhoneNumber.PhoneNumberUtil.getInstance()\n\nexport const COUNTRY = 'GB'\nexport const INVALID_ERROR_CODE = 'phoneNumber.invalid'\n\nexport const isUKNumber = (value: LibPhoneNumber.PhoneNumber) => {\n return phoneUtil.isValidNumberForRegion(value, COUNTRY)\n}\n\nexport const joi = JoiBase.extend({\n type: 'string',\n base: JoiBase.string(),\n messages: {\n [INVALID_ERROR_CODE]: messageTemplate.format\n } as LanguageMessages,\n rules: {\n phoneNumber: {\n method({\n format\n }: { format?: TelephoneNumberFieldOptionsFormatEnum } = {}) {\n return this.$_addRule({\n name: 'phoneNumber',\n args: { format }\n })\n },\n args: [\n {\n name: 'format',\n ref: true,\n assert: JoiBase.valid(\n TelephoneNumberFieldOptionsFormatEnum.International,\n TelephoneNumberFieldOptionsFormatEnum.UK\n )\n }\n ],\n validate(value, { error }, args) {\n const format = args.format\n\n try {\n const parsed = phoneUtil.parse(value, COUNTRY)\n\n if (!phoneUtil.isValidNumber(parsed)) {\n return error(INVALID_ERROR_CODE)\n }\n\n if (format) {\n const isUK = isUKNumber(parsed)\n\n if (\n (!isUK && format === TelephoneNumberFieldOptionsFormatEnum.UK) ||\n (isUK &&\n format === TelephoneNumberFieldOptionsFormatEnum.International)\n ) {\n return error(INVALID_ERROR_CODE)\n }\n }\n\n return value\n } catch {\n return error(INVALID_ERROR_CODE)\n }\n }\n }\n }\n}) as JoiBase.Root\n"],"mappings":"AAAA,SAASA,qCAAqC,QAAQ,oBAAoB;AAC1E,OAAOC,cAAc,MAAM,uBAAuB;AAClD,OAAOC,OAAO,MAAiC,KAAK;AAEpD,SAASC,eAAe;AAExB,MAAMC,SAAS,GAAGH,cAAc,CAACI,eAAe,CAACC,WAAW,CAAC,CAAC;AAE9D,OAAO,MAAMC,OAAO,GAAG,IAAI;AAC3B,OAAO,MAAMC,kBAAkB,GAAG,qBAAqB;AAEvD,OAAO,MAAMC,UAAU,GAAIC,KAAiC,IAAK;EAC/D,OAAON,SAAS,CAACO,sBAAsB,CAACD,KAAK,EAAEH,OAAO,CAAC;AACzD,CAAC;AAED,OAAO,MAAMK,GAAG,GAAGV,OAAO,CAACW,MAAM,CAAC;EAChCC,IAAI,EAAE,QAAQ;EACdC,IAAI,EAAEb,OAAO,CAACc,MAAM,CAAC,CAAC;EACtBC,QAAQ,EAAE;IACR,CAACT,kBAAkB,GAAGL,eAAe,CAACe;EACxC,CAAqB;EACrBC,KAAK,EAAE;IACLC,WAAW,EAAE;MACXC,MAAMA,CAAC;QACLH;MACkD,CAAC,GAAG,CAAC,CAAC,EAAE;QAC1D,OAAO,IAAI,CAACI,SAAS,CAAC;UACpBC,IAAI,EAAE,aAAa;UACnBC,IAAI,EAAE;YAAEN;UAAO;QACjB,CAAC,CAAC;MACJ,CAAC;MACDM,IAAI,EAAE,CACJ;QACED,IAAI,EAAE,QAAQ;QACdE,GAAG,EAAE,IAAI;QACTC,MAAM,EAAExB,OAAO,CAACyB,KAAK,CACnB3B,qCAAqC,CAAC4B,aAAa,EACnD5B,qCAAqC,CAAC6B,EACxC;MACF,CAAC,CACF;MACDC,QAAQA,CAACpB,KAAK,EAAE;QAAEqB;MAAM,CAAC,EAAEP,IAAI,EAAE;QAC/B,MAAMN,MAAM,GAAGM,IAAI,CAACN,MAAM;QAE1B,IAAI;UACF,MAAMc,MAAM,GAAG5B,SAAS,CAAC6B,KAAK,CAACvB,KAAK,EAAEH,OAAO,CAAC;UAE9C,IAAI,CAACH,SAAS,CAAC8B,aAAa,CAACF,MAAM,CAAC,EAAE;YACpC,OAAOD,KAAK,CAACvB,kBAAkB,CAAC;UAClC;UAEA,IAAIU,MAAM,EAAE;YACV,MAAMiB,IAAI,GAAG1B,UAAU,CAACuB,MAAM,CAAC;YAE/B,IACG,CAACG,IAAI,IAAIjB,MAAM,KAAKlB,qCAAqC,CAAC6B,EAAE,IAC5DM,IAAI,IACHjB,MAAM,KAAKlB,qCAAqC,CAAC4B,aAAc,EACjE;cACA,OAAOG,KAAK,CAACvB,kBAAkB,CAAC;YAClC;UACF;UAEA,OAAOE,KAAK;QACd,CAAC,CAAC,MAAM;UACN,OAAOqB,KAAK,CAACvB,kBAAkB,CAAC;QAClC;MACF;IACF;EACF;AACF,CAAC,CAAiB","ignoreList":[]}
@@ -0,0 +1,90 @@
1
+ import { TelephoneNumberFieldOptionsFormatEnum } from '@defra/forms-model';
2
+ import { joi } from "./telephone.js";
3
+ describe('Telephone validation helpers', () => {
4
+ describe('UK numbers', () => {
5
+ test('it should not have errors for valid telephone number', () => {
6
+ const telephoneSchema = joi.string().phoneNumber({
7
+ format: TelephoneNumberFieldOptionsFormatEnum.UK
8
+ }).label('Home phone');
9
+ const result = telephoneSchema.validate('0160676477');
10
+ expect(result.error).toBeUndefined();
11
+ expect(result.value).toBe('0160676477');
12
+ });
13
+ test('it should not have errors for valid UK telephone number in international format', () => {
14
+ const telephoneSchema = joi.string().phoneNumber({
15
+ format: TelephoneNumberFieldOptionsFormatEnum.UK
16
+ }).label('Home phone');
17
+ const result = telephoneSchema.validate('+44 1606 76477');
18
+ expect(result.error).toBeUndefined();
19
+ expect(result.value).toBe('+44 1606 76477');
20
+ });
21
+ test('it should have errors for invalid telephone number', () => {
22
+ const telephoneSchema = joi.string().phoneNumber({
23
+ format: TelephoneNumberFieldOptionsFormatEnum.UK
24
+ }).label('Home phone');
25
+ const result = telephoneSchema.validate('ABC');
26
+ expect(result.error).toBeDefined();
27
+ expect(result.error?.message).toBe('Enter home phone in the correct format');
28
+ expect(result.value).toBe('ABC');
29
+ });
30
+ test('it should have errors for international telephone number', () => {
31
+ const telephoneSchema = joi.string().phoneNumber({
32
+ format: TelephoneNumberFieldOptionsFormatEnum.UK
33
+ }).label('Home phone');
34
+ const result = telephoneSchema.validate('+1-212-456-7890');
35
+ expect(result.error).toBeDefined();
36
+ expect(result.error?.message).toBe('Enter home phone in the correct format');
37
+ expect(result.value).toBe('+1-212-456-7890');
38
+ });
39
+ });
40
+ describe('International numbers', () => {
41
+ test('it should not have errors for valid telephone number', () => {
42
+ const telephoneSchema = joi.string().phoneNumber({
43
+ format: TelephoneNumberFieldOptionsFormatEnum.International
44
+ }).label('Home phone');
45
+ const result = telephoneSchema.validate('+1-212-456-7890');
46
+ expect(result.error).toBeUndefined();
47
+ expect(result.value).toBe('+1-212-456-7890');
48
+ });
49
+ test('it should have errors for invalid telephone number', () => {
50
+ const telephoneSchema = joi.string().phoneNumber({
51
+ format: TelephoneNumberFieldOptionsFormatEnum.International
52
+ }).label('Home phone');
53
+ const result = telephoneSchema.validate('ABC');
54
+ expect(result.error).toBeDefined();
55
+ expect(result.error?.message).toBe('Enter home phone in the correct format');
56
+ expect(result.value).toBe('ABC');
57
+ });
58
+ test('it should have errors for UK phone number in international format', () => {
59
+ const telephoneSchema = joi.string().phoneNumber({
60
+ format: TelephoneNumberFieldOptionsFormatEnum.International
61
+ }).label('Home phone');
62
+ const result = telephoneSchema.validate('+44 1606 76477');
63
+ expect(result.error).toBeDefined();
64
+ expect(result.error?.message).toBe('Enter home phone in the correct format');
65
+ expect(result.value).toBe('+44 1606 76477');
66
+ });
67
+ });
68
+ describe('Any format', () => {
69
+ test('it should not have errors for valid national telephone number', () => {
70
+ const telephoneSchema = joi.string().phoneNumber().label('Home phone');
71
+ const result = telephoneSchema.validate('0160676477');
72
+ expect(result.error).toBeUndefined();
73
+ expect(result.value).toBe('0160676477');
74
+ });
75
+ test('it should not have errors for valid international telephone number', () => {
76
+ const telephoneSchema = joi.string().phoneNumber().label('Home phone');
77
+ const result = telephoneSchema.validate('+1-212-456-7890');
78
+ expect(result.error).toBeUndefined();
79
+ expect(result.value).toBe('+1-212-456-7890');
80
+ });
81
+ test('it should have errors for invalid telephone number', () => {
82
+ const telephoneSchema = joi.string().phoneNumber().label('Home phone');
83
+ const result = telephoneSchema.validate('ABC');
84
+ expect(result.error).toBeDefined();
85
+ expect(result.error?.message).toBe('Enter home phone in the correct format');
86
+ expect(result.value).toBe('ABC');
87
+ });
88
+ });
89
+ });
90
+ //# sourceMappingURL=telephone.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telephone.test.js","names":["TelephoneNumberFieldOptionsFormatEnum","joi","describe","test","telephoneSchema","string","phoneNumber","format","UK","label","result","validate","expect","error","toBeUndefined","value","toBe","toBeDefined","message","International"],"sources":["../../../../../../src/server/plugins/engine/components/helpers/telephone.test.js"],"sourcesContent":["import { TelephoneNumberFieldOptionsFormatEnum } from '@defra/forms-model'\n\nimport { joi } from '~/src/server/plugins/engine/components/helpers/telephone.js'\n\ndescribe('Telephone validation helpers', () => {\n describe('UK numbers', () => {\n test('it should not have errors for valid telephone number', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({ format: TelephoneNumberFieldOptionsFormatEnum.UK })\n .label('Home phone')\n\n const result = telephoneSchema.validate('0160676477')\n\n expect(result.error).toBeUndefined()\n expect(result.value).toBe('0160676477')\n })\n\n test('it should not have errors for valid UK telephone number in international format', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({ format: TelephoneNumberFieldOptionsFormatEnum.UK })\n .label('Home phone')\n\n const result = telephoneSchema.validate('+44 1606 76477')\n\n expect(result.error).toBeUndefined()\n expect(result.value).toBe('+44 1606 76477')\n })\n\n test('it should have errors for invalid telephone number', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({ format: TelephoneNumberFieldOptionsFormatEnum.UK })\n .label('Home phone')\n\n const result = telephoneSchema.validate('ABC')\n\n expect(result.error).toBeDefined()\n expect(result.error?.message).toBe(\n 'Enter home phone in the correct format'\n )\n expect(result.value).toBe('ABC')\n })\n\n test('it should have errors for international telephone number', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({ format: TelephoneNumberFieldOptionsFormatEnum.UK })\n .label('Home phone')\n\n const result = telephoneSchema.validate('+1-212-456-7890')\n\n expect(result.error).toBeDefined()\n expect(result.error?.message).toBe(\n 'Enter home phone in the correct format'\n )\n expect(result.value).toBe('+1-212-456-7890')\n })\n })\n\n describe('International numbers', () => {\n test('it should not have errors for valid telephone number', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({\n format: TelephoneNumberFieldOptionsFormatEnum.International\n })\n .label('Home phone')\n\n const result = telephoneSchema.validate('+1-212-456-7890')\n\n expect(result.error).toBeUndefined()\n expect(result.value).toBe('+1-212-456-7890')\n })\n\n test('it should have errors for invalid telephone number', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({\n format: TelephoneNumberFieldOptionsFormatEnum.International\n })\n .label('Home phone')\n\n const result = telephoneSchema.validate('ABC')\n\n expect(result.error).toBeDefined()\n expect(result.error?.message).toBe(\n 'Enter home phone in the correct format'\n )\n expect(result.value).toBe('ABC')\n })\n\n test('it should have errors for UK phone number in international format', () => {\n const telephoneSchema = joi\n .string()\n .phoneNumber({\n format: TelephoneNumberFieldOptionsFormatEnum.International\n })\n .label('Home phone')\n\n const result = telephoneSchema.validate('+44 1606 76477')\n\n expect(result.error).toBeDefined()\n expect(result.error?.message).toBe(\n 'Enter home phone in the correct format'\n )\n expect(result.value).toBe('+44 1606 76477')\n })\n })\n\n describe('Any format', () => {\n test('it should not have errors for valid national telephone number', () => {\n const telephoneSchema = joi.string().phoneNumber().label('Home phone')\n\n const result = telephoneSchema.validate('0160676477')\n\n expect(result.error).toBeUndefined()\n expect(result.value).toBe('0160676477')\n })\n\n test('it should not have errors for valid international telephone number', () => {\n const telephoneSchema = joi.string().phoneNumber().label('Home phone')\n\n const result = telephoneSchema.validate('+1-212-456-7890')\n\n expect(result.error).toBeUndefined()\n expect(result.value).toBe('+1-212-456-7890')\n })\n\n test('it should have errors for invalid telephone number', () => {\n const telephoneSchema = joi.string().phoneNumber().label('Home phone')\n\n const result = telephoneSchema.validate('ABC')\n\n expect(result.error).toBeDefined()\n expect(result.error?.message).toBe(\n 'Enter home phone in the correct format'\n )\n expect(result.value).toBe('ABC')\n })\n })\n})\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,5 @@
1
- import { type JoiExpression, type LanguageMessages, type LanguageMessagesExt, type ValidationOptions } from 'joi';
1
+ import { type JoiExpression, type LanguageMessages, type LanguageMessagesExt, type ReferenceOptions, type ValidationOptions } from 'joi';
2
+ export declare const opts: ReferenceOptions;
2
3
  /**
3
4
  * see @link https://joi.dev/api/?v=17.4.2#template-syntax for template syntax
4
5
  */
@@ -2,7 +2,7 @@
2
2
 
3
3
  import joi from 'joi';
4
4
  import { lowerFirstPreserveProperNouns } from "../components/helpers/index.js";
5
- const opts = {
5
+ export const opts = {
6
6
  functions: {
7
7
  lowerFirst: lowerFirstPreserveProperNouns
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validationOptions.js","names":["joi","lowerFirstPreserveProperNouns","opts","functions","lowerFirst","messageTemplate","declarationRequired","expression","required","selectRequired","selectYesNoRequired","max","min","minMax","pattern","format","unicode","number","numberPrecision","numberInteger","numberMin","numberMax","maxWords","objectRequired","objectMissing","dateFormat","dateMin","dateMax","arrayMin","arrayMax","arrayLength","featuresMin","featuresMax","featuresLength","messages","messagesPre","validationOptions","abortEarly","errors","wrap","array","label"],"sources":["../../../../../src/server/plugins/engine/pageControllers/validationOptions.ts"],"sourcesContent":["// Declaration above is needed for: https://github.com/hapijs/joi/issues/3064\n\nimport joi, {\n type JoiExpression,\n type LanguageMessages,\n type LanguageMessagesExt,\n type ReferenceOptions,\n type ValidationOptions\n} from 'joi'\n\nimport { lowerFirstPreserveProperNouns } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nconst opts = {\n functions: {\n lowerFirst: lowerFirstPreserveProperNouns\n }\n} as ReferenceOptions\n\n/**\n * see @link https://joi.dev/api/?v=17.4.2#template-syntax for template syntax\n */\nexport const messageTemplate: Record<string, JoiExpression> = {\n declarationRequired: joi.expression(\n 'You must confirm you understand and agree with the {{lowerFirst(#label)}} to continue',\n opts\n ) as JoiExpression,\n required: joi.expression(\n 'Enter {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectRequired: joi.expression(\n 'Select {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectYesNoRequired: '{{#label}} - select yes or no',\n max: '{{#label}} must be {{#limit}} characters or less',\n min: '{{#label}} must be {{#limit}} characters or more',\n minMax: '{{#label}} must be between {{#min}} and {{#max}} characters',\n pattern: joi.expression(\n 'Enter a valid {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n format: joi.expression(\n 'Enter {{lowerFirst(#label)}} in the correct format',\n opts\n ) as JoiExpression,\n unicode: '{{#label}} includes invalid characters, for example, long dashes',\n number: '{{#label}} must be a number',\n numberPrecision: '{{#label}} must have {{#limit}} or fewer decimal places',\n numberInteger: '{{#label}} must be a whole number',\n numberMin: '{{#label}} must be {{#limit}} or higher',\n numberMax: '{{#label}} must be {{#limit}} or lower',\n maxWords: '{{#label}} must be {{#limit}} words or fewer',\n\n // Nested fields use component title\n\n objectRequired: joi.expression('Enter {{#label}}', opts) as JoiExpression,\n objectMissing: joi.expression(\n '{{#title}} must include a {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n dateFormat: '{{#title}} must be a real date',\n dateMin: '{{#title}} must be the same as or after {{#limit}}',\n dateMax: '{{#title}} must be the same as or before {{#limit}}',\n arrayMin: 'Select at least {{#limit}} options from the list',\n arrayMax: 'Only {{#limit}} can be selected from the list',\n arrayLength: 'Select only {{#limit}} options from the list',\n featuresMin: 'Define at least {{#limit}} features',\n featuresMax: 'Only {{#limit}} features can be defined',\n featuresLength: 'Define exactly {{#limit}} features'\n}\n\nexport const messages: LanguageMessagesExt = {\n 'string.base': messageTemplate.required,\n 'string.min': messageTemplate.min,\n 'string.empty': messageTemplate.required,\n 'string.max': messageTemplate.max,\n 'string.email': messageTemplate.format,\n 'string.unicode': messageTemplate.unicode,\n 'string.pattern.base': messageTemplate.pattern,\n 'string.maxWords': messageTemplate.maxWords,\n\n 'number.base': messageTemplate.number,\n 'number.precision': messageTemplate.numberPrecision,\n 'number.integer': messageTemplate.numberInteger,\n 'number.unsafe': messageTemplate.format,\n 'number.min': messageTemplate.numberMin,\n 'number.max': messageTemplate.numberMax,\n\n 'object.required': messageTemplate.objectRequired,\n 'object.and': messageTemplate.objectMissing,\n\n 'any.only': messageTemplate.selectRequired,\n 'any.required': messageTemplate.selectRequired,\n 'any.empty': messageTemplate.required,\n\n 'date.base': messageTemplate.dateFormat,\n 'date.format': messageTemplate.dateFormat,\n 'date.min': messageTemplate.dateMin,\n 'date.max': messageTemplate.dateMax,\n\n 'object.invalidjson': messageTemplate.format\n}\n\nexport const messagesPre: LanguageMessages =\n messages as unknown as LanguageMessages\n\nexport const validationOptions: ValidationOptions = {\n abortEarly: false,\n messages: messagesPre,\n errors: {\n wrap: {\n array: false,\n label: false\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"validationOptions.js","names":["joi","lowerFirstPreserveProperNouns","opts","functions","lowerFirst","messageTemplate","declarationRequired","expression","required","selectRequired","selectYesNoRequired","max","min","minMax","pattern","format","unicode","number","numberPrecision","numberInteger","numberMin","numberMax","maxWords","objectRequired","objectMissing","dateFormat","dateMin","dateMax","arrayMin","arrayMax","arrayLength","featuresMin","featuresMax","featuresLength","messages","messagesPre","validationOptions","abortEarly","errors","wrap","array","label"],"sources":["../../../../../src/server/plugins/engine/pageControllers/validationOptions.ts"],"sourcesContent":["// Declaration above is needed for: https://github.com/hapijs/joi/issues/3064\n\nimport joi, {\n type JoiExpression,\n type LanguageMessages,\n type LanguageMessagesExt,\n type ReferenceOptions,\n type ValidationOptions\n} from 'joi'\n\nimport { lowerFirstPreserveProperNouns } from '~/src/server/plugins/engine/components/helpers/index.js'\n\nexport const opts = {\n functions: {\n lowerFirst: lowerFirstPreserveProperNouns\n }\n} as ReferenceOptions\n\n/**\n * see @link https://joi.dev/api/?v=17.4.2#template-syntax for template syntax\n */\nexport const messageTemplate: Record<string, JoiExpression> = {\n declarationRequired: joi.expression(\n 'You must confirm you understand and agree with the {{lowerFirst(#label)}} to continue',\n opts\n ) as JoiExpression,\n required: joi.expression(\n 'Enter {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectRequired: joi.expression(\n 'Select {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n selectYesNoRequired: '{{#label}} - select yes or no',\n max: '{{#label}} must be {{#limit}} characters or less',\n min: '{{#label}} must be {{#limit}} characters or more',\n minMax: '{{#label}} must be between {{#min}} and {{#max}} characters',\n pattern: joi.expression(\n 'Enter a valid {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n format: joi.expression(\n 'Enter {{lowerFirst(#label)}} in the correct format',\n opts\n ) as JoiExpression,\n unicode: '{{#label}} includes invalid characters, for example, long dashes',\n number: '{{#label}} must be a number',\n numberPrecision: '{{#label}} must have {{#limit}} or fewer decimal places',\n numberInteger: '{{#label}} must be a whole number',\n numberMin: '{{#label}} must be {{#limit}} or higher',\n numberMax: '{{#label}} must be {{#limit}} or lower',\n maxWords: '{{#label}} must be {{#limit}} words or fewer',\n\n // Nested fields use component title\n\n objectRequired: joi.expression('Enter {{#label}}', opts) as JoiExpression,\n objectMissing: joi.expression(\n '{{#title}} must include a {{lowerFirst(#label)}}',\n opts\n ) as JoiExpression,\n dateFormat: '{{#title}} must be a real date',\n dateMin: '{{#title}} must be the same as or after {{#limit}}',\n dateMax: '{{#title}} must be the same as or before {{#limit}}',\n arrayMin: 'Select at least {{#limit}} options from the list',\n arrayMax: 'Only {{#limit}} can be selected from the list',\n arrayLength: 'Select only {{#limit}} options from the list',\n featuresMin: 'Define at least {{#limit}} features',\n featuresMax: 'Only {{#limit}} features can be defined',\n featuresLength: 'Define exactly {{#limit}} features'\n}\n\nexport const messages: LanguageMessagesExt = {\n 'string.base': messageTemplate.required,\n 'string.min': messageTemplate.min,\n 'string.empty': messageTemplate.required,\n 'string.max': messageTemplate.max,\n 'string.email': messageTemplate.format,\n 'string.unicode': messageTemplate.unicode,\n 'string.pattern.base': messageTemplate.pattern,\n 'string.maxWords': messageTemplate.maxWords,\n\n 'number.base': messageTemplate.number,\n 'number.precision': messageTemplate.numberPrecision,\n 'number.integer': messageTemplate.numberInteger,\n 'number.unsafe': messageTemplate.format,\n 'number.min': messageTemplate.numberMin,\n 'number.max': messageTemplate.numberMax,\n\n 'object.required': messageTemplate.objectRequired,\n 'object.and': messageTemplate.objectMissing,\n\n 'any.only': messageTemplate.selectRequired,\n 'any.required': messageTemplate.selectRequired,\n 'any.empty': messageTemplate.required,\n\n 'date.base': messageTemplate.dateFormat,\n 'date.format': messageTemplate.dateFormat,\n 'date.min': messageTemplate.dateMin,\n 'date.max': messageTemplate.dateMax,\n\n 'object.invalidjson': messageTemplate.format\n}\n\nexport const messagesPre: LanguageMessages =\n messages as unknown as LanguageMessages\n\nexport const validationOptions: ValidationOptions = {\n abortEarly: false,\n messages: messagesPre,\n errors: {\n wrap: {\n array: false,\n label: false\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.js","names":[],"sources":["../../../src/typings/joi/index.d.ts"],"sourcesContent":["import { type FormPayload } from '~/src/server/plugins/engine/types.ts'\n\ndeclare module 'joi' {\n interface Context {\n present?: string[]\n presentWithLabels?: string[]\n missing?: string[]\n missingWithLabels?: string[]\n }\n\n /**\n * Add context types for `object.and` error reports\n * {@link https://joi.dev/api/?v=17.13.3#objectand}\n */\n interface ErrorReportCollection extends ErrorReport {\n local: Context & {\n value: FormPayload\n label?: string\n title?: string\n }\n }\n\n interface JoiExpressionReturn {\n render: (p1, p2, p3, p4, p5) => string\n }\n\n type JoiExpression = JoiExpressionReturn | string\n\n type LanguageMessagesExt = Record<string, JoiExpression>\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"index.d.js","names":[],"sources":["../../../src/typings/joi/index.d.ts"],"sourcesContent":["import { type FormPayload } from '~/src/server/plugins/engine/types.ts'\n\ndeclare module 'joi' {\n interface Context {\n present?: string[]\n presentWithLabels?: string[]\n missing?: string[]\n missingWithLabels?: string[]\n }\n\n /**\n * Add context types for `object.and` error reports\n * {@link https://joi.dev/api/?v=17.13.3#objectand}\n */\n interface ErrorReportCollection extends ErrorReport {\n local: Context & {\n value: FormPayload\n label?: string\n title?: string\n }\n }\n\n interface JoiExpressionReturn {\n render: (p1, p2, p3, p4, p5) => string\n }\n\n type JoiExpression = JoiExpressionReturn | string\n\n type LanguageMessagesExt = Record<string, JoiExpression>\n\n interface PhoneNumberOptions {\n format?: 'international' | 'uk' | undefined\n }\n\n interface StringSchema {\n phoneNumber(options?: PhoneNumberOptions): this\n }\n}\n"],"mappings":"","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/forms-engine-plugin",
3
- "version": "4.14.2",
3
+ "version": "4.14.4",
4
4
  "description": "Defra forms engine",
5
5
  "type": "module",
6
6
  "files": [
@@ -87,7 +87,7 @@
87
87
  },
88
88
  "license": "SEE LICENSE IN LICENSE",
89
89
  "dependencies": {
90
- "@defra/forms-model": "^3.0.668",
90
+ "@defra/forms-model": "^3.0.674",
91
91
  "@defra/hapi-tracing": "^1.29.0",
92
92
  "@defra/interactive-map": "^0.0.22-alpha",
93
93
  "@elastic/ecs-pino-format": "^1.5.0",
@@ -119,6 +119,7 @@
119
119
  "dotenv": "^17.2.3",
120
120
  "expr-eval-fork": "^3.0.0",
121
121
  "geodesy": "^2.4.0",
122
+ "google-libphonenumber": "^3.2.44",
122
123
  "govuk-frontend": "^5.13.0",
123
124
  "hapi-pino": "^13.0.0",
124
125
  "hapi-pulse": "^3.0.1",
@@ -157,6 +158,7 @@
157
158
  "@types/btoa": "^1.2.5",
158
159
  "@types/convict": "^6.1.6",
159
160
  "@types/eslint": "^9.6.1",
161
+ "@types/google-libphonenumber": "^7.4.30",
160
162
  "@types/govuk-frontend": "^5.11.0",
161
163
  "@types/hapi": "^18.0.15",
162
164
  "@types/hapi__catbox-memory": "^6.0.2",
@@ -1,8 +1,12 @@
1
1
  import { type TelephoneNumberFieldComponent } from '@defra/forms-model'
2
- import joi, { type StringSchema } from 'joi'
2
+ import { type StringSchema } from 'joi'
3
3
 
4
4
  import { FormComponent } from './FormComponent.js'
5
5
  import { addClassOptionIfNone } from './helpers/index.js'
6
+ import {
7
+ INVALID_ERROR_CODE,
8
+ joi
9
+ } from './helpers/telephone.js'
6
10
  import { messageTemplate } from '../pageControllers/validationOptions.js'
7
11
  import {
8
12
  type ErrorMessageTemplateList,
@@ -10,8 +14,6 @@ import {
10
14
  type FormSubmissionError
11
15
  } from '../types.js'
12
16
 
13
- const PATTERN = /^[0-9\\\s+()-]*$/
14
-
15
17
  export class TelephoneNumberField extends FormComponent {
16
18
  declare options: TelephoneNumberFieldComponent['options']
17
19
  declare formSchema: StringSchema
@@ -24,11 +26,12 @@ export class TelephoneNumberField extends FormComponent {
24
26
  super(def, props)
25
27
 
26
28
  const { options } = def
29
+ const { format } = options
27
30
 
28
31
  let formSchema = joi
29
32
  .string()
30
33
  .trim()
31
- .pattern(PATTERN)
34
+ .phoneNumber({ format })
32
35
  .label(this.label)
33
36
  .required()
34
37
 
@@ -42,7 +45,8 @@ export class TelephoneNumberField extends FormComponent {
42
45
  formSchema = formSchema.messages({
43
46
  'any.required': message,
44
47
  'string.empty': message,
45
- 'string.pattern.base': message
48
+ 'string.pattern.base': message,
49
+ [INVALID_ERROR_CODE]: message
46
50
  })
47
51
  } else if (options.customValidationMessages) {
48
52
  formSchema = formSchema.messages(options.customValidationMessages)
@@ -171,7 +171,3 @@ export function getGeospatialSchema(
171
171
  def
172
172
  )
173
173
  }
174
-
175
- /**
176
- * @import { CustomHelpers } from 'joi'
177
- */
@@ -0,0 +1,71 @@
1
+ import { TelephoneNumberFieldOptionsFormatEnum } from '@defra/forms-model'
2
+ import LibPhoneNumber from 'google-libphonenumber'
3
+ import JoiBase, { type LanguageMessages } from 'joi'
4
+
5
+ import { messageTemplate } from '../../pageControllers/validationOptions.js'
6
+
7
+ const phoneUtil = LibPhoneNumber.PhoneNumberUtil.getInstance()
8
+
9
+ export const COUNTRY = 'GB'
10
+ export const INVALID_ERROR_CODE = 'phoneNumber.invalid'
11
+
12
+ export const isUKNumber = (value: LibPhoneNumber.PhoneNumber) => {
13
+ return phoneUtil.isValidNumberForRegion(value, COUNTRY)
14
+ }
15
+
16
+ export const joi = JoiBase.extend({
17
+ type: 'string',
18
+ base: JoiBase.string(),
19
+ messages: {
20
+ [INVALID_ERROR_CODE]: messageTemplate.format
21
+ } as LanguageMessages,
22
+ rules: {
23
+ phoneNumber: {
24
+ method({
25
+ format
26
+ }: { format?: TelephoneNumberFieldOptionsFormatEnum } = {}) {
27
+ return this.$_addRule({
28
+ name: 'phoneNumber',
29
+ args: { format }
30
+ })
31
+ },
32
+ args: [
33
+ {
34
+ name: 'format',
35
+ ref: true,
36
+ assert: JoiBase.valid(
37
+ TelephoneNumberFieldOptionsFormatEnum.International,
38
+ TelephoneNumberFieldOptionsFormatEnum.UK
39
+ )
40
+ }
41
+ ],
42
+ validate(value, { error }, args) {
43
+ const format = args.format
44
+
45
+ try {
46
+ const parsed = phoneUtil.parse(value, COUNTRY)
47
+
48
+ if (!phoneUtil.isValidNumber(parsed)) {
49
+ return error(INVALID_ERROR_CODE)
50
+ }
51
+
52
+ if (format) {
53
+ const isUK = isUKNumber(parsed)
54
+
55
+ if (
56
+ (!isUK && format === TelephoneNumberFieldOptionsFormatEnum.UK) ||
57
+ (isUK &&
58
+ format === TelephoneNumberFieldOptionsFormatEnum.International)
59
+ ) {
60
+ return error(INVALID_ERROR_CODE)
61
+ }
62
+ }
63
+
64
+ return value
65
+ } catch {
66
+ return error(INVALID_ERROR_CODE)
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }) as JoiBase.Root
@@ -10,7 +10,7 @@ import joi, {
10
10
 
11
11
  import { lowerFirstPreserveProperNouns } from '../components/helpers/index.js'
12
12
 
13
- const opts = {
13
+ export const opts = {
14
14
  functions: {
15
15
  lowerFirst: lowerFirstPreserveProperNouns
16
16
  }
@@ -27,4 +27,12 @@ declare module 'joi' {
27
27
  type JoiExpression = JoiExpressionReturn | string
28
28
 
29
29
  type LanguageMessagesExt = Record<string, JoiExpression>
30
+
31
+ interface PhoneNumberOptions {
32
+ format?: 'international' | 'uk' | undefined
33
+ }
34
+
35
+ interface StringSchema {
36
+ phoneNumber(options?: PhoneNumberOptions): this
37
+ }
30
38
  }