@dwp/govuk-casa
Version:
A framework for building GOVUK Collect-And-Submit-Applications
166 lines • 7.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = __importDefault(require("lodash"));
const ValidationError_js_1 = __importDefault(require("../ValidationError.js"));
const ValidatorFactory_js_1 = __importDefault(require("../ValidatorFactory.js"));
const utils_js_1 = require("../utils.js");
const { isPlainObject } = lodash_1.default; // CommonjS
/**
* @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
* @access private
*/
/**
* @typedef {object} PostalAddressObjectConfigOptions
* @property {ErrorMessageConfig} [errorMsg] General error message for the
* entire address block
* @property {string | object} [errorMsgAddress1] Error message for address1
* part
* @property {string | object} [errorMsgAddress2] Error message for address2
* part
* @property {string | object} [errorMsgAddress3] Error message for address3
* part
* @property {string | object} [errorMsgAddress4] Error message for address4
* part
* @property {string | object} [errorMsgPostcode] Error message for postcode
* part
* @property {number} [strlenmax] Max. String length for each of the inputs
* address[1-4]
* @property {string[]} [requiredFields] Field parts required (others become
* optional). One of 'address1'|'address2'|'address3'|'address4'|'postcode'
*/
/**
* Works hand in hand with the core CASA `postalAddressObject` form macro.
*
* The errors sent back from this validator are specific to each subfield. For
* example, if the field name being tested is "address", any errors related to
* the "postcode" component would be associated with "address[postcode]".
*
* See {@link PostalAddressObjectConfigOptions} for `make()` options.
*
* @memberof Validators
* @augments ValidatorFactory
*/
class PostalAddressObject extends ValidatorFactory_js_1.default {
name = "postalAddressObject";
validate(value, dataContext = {}) {
const cfg = {
requiredFields: ["address1", "address3", "postcode"],
strlenmax: undefined,
errorMsgAddress1: {
inline: "validation:rule.postalAddressObject.address1.inline",
summary: "validation:rule.postalAddressObject.address1.summary",
focusSuffix: "[address1]",
},
errorMsgAddress2: {
inline: "validation:rule.postalAddressObject.address2.inline",
summary: "validation:rule.postalAddressObject.address2.summary",
focusSuffix: "[address2]",
},
errorMsgAddress3: {
inline: "validation:rule.postalAddressObject.address3.inline",
summary: "validation:rule.postalAddressObject.address3.summary",
focusSuffix: "[address3]",
},
errorMsgAddress4: {
inline: "validation:rule.postalAddressObject.address4.inline",
summary: "validation:rule.postalAddressObject.address4.summary",
focusSuffix: "[address4]",
},
errorMsgPostcode: {
inline: "validation:rule.postalAddressObject.postcode.inline",
summary: "validation:rule.postalAddressObject.postcode.summary",
focusSuffix: "[postcode]",
},
errorMsg: {
inline: "validation:rule.postalAddressObject.group.inline",
summary: "validation:rule.postalAddressObject.group.summary",
focusSuffix: "[address1]",
},
...this.config,
};
const objectifyError = (err) => typeof err === "string"
? {
inline: err,
summary: err,
}
: err;
// Work out required/optional parts based on config
const reqF = Object.create(null);
const reqC = cfg.requiredFields;
reqF.address1 = reqC.indexOf("address1") > -1;
reqF.address2 = reqC.indexOf("address2") > -1;
reqF.address3 = reqC.indexOf("address3") > -1;
reqF.address4 = reqC.indexOf("address4") > -1;
reqF.postcode = reqC.indexOf("postcode") > -1;
let valid = true;
const errorMsgs = [];
if (typeof value === "object") {
const reAddr = /^[a-z0-9\-,.&#()/\\:;'" ]{2,}$/i;
const reAddrLine1 = /^(\d+|[a-z0-9\-,.&#()/\\:;'" ]{2,})$/i;
// UK Postcode regex taken from the dwp java pc checker
// https://github.com/dwp/postcode-format-validation
/* eslint-disable sonarjs/regex-complexity */
const rePostcode = /^(?![QVX])[A-Z]((?![IJZ])[A-Z]\d((\d?)|([ABEHMNPRVWXY]?))|(\d(\d?|[ABCDEFGHJKPSTUW]?))) ?\d((?![CIKMOV])[A-Z]){2}$|^(BFPO) ?\d{1,4}$/i;
/* eslint-enable sonarjs/regex-complexity */
// [required, regex, strlenmax, error message]
const attributes = {
address1: [
reqF.address1,
reAddrLine1,
cfg.strlenmax,
cfg.errorMsgAddress1,
],
address2: [reqF.address2, reAddr, cfg.strlenmax, cfg.errorMsgAddress2],
address3: [reqF.address3, reAddr, cfg.strlenmax, cfg.errorMsgAddress3],
address4: [reqF.address4, reAddr, cfg.strlenmax, cfg.errorMsgAddress4],
postcode: [reqF.postcode, rePostcode, null, cfg.errorMsgPostcode],
};
// ESLint disabled as `k` is a known value from the constant list above
/* eslint-disable security/detect-object-injection */
for (const k of Object.keys(attributes)) {
const attr = attributes[k];
const hasProperty = Object.hasOwn(value, k);
const hasContent = hasProperty && value[k].length > 0;
const condMissingOrRegexMismatch = (attr[0] || hasContent) && (!hasProperty || !value[k].match(attr[1]));
const condExceedStrlen = attr[2] > 0 && hasContent && String(value[k]).length > attr[2];
if (condMissingOrRegexMismatch || condExceedStrlen) {
valid = false;
errorMsgs.push(Object.assign(Object.create(null), objectifyError(attr[3]), {
fieldKeySuffix: `[${k}]`,
}));
}
}
/* eslint-enable security/detect-object-injection */
}
else {
valid = false;
errorMsgs.push(cfg.errorMsg);
}
// Build ValidationErrorGroup
const errorGroup = errorMsgs.map((err) => ValidationError_js_1.default.make({ errorMsg: err, dataContext }));
return valid ? [] : [...errorGroup];
}
sanitise(value) {
// Only objects are supported
if (!isPlainObject(value)) {
return Object.create(null);
}
// Prune unrecognised attributes, and coerce to Strings
const validKeys = [
"address1",
"address2",
"address3",
"address4",
"postcode",
];
const pruned = Object.fromEntries(Object.entries(value)
.filter(([k]) => validKeys.includes(k))
.map(([k, v]) => [k, (0, utils_js_1.stringifyInput)(v)]));
return Object.assign(Object.create(null), pruned);
}
}
exports.default = PostalAddressObject;
//# sourceMappingURL=postalAddressObject.js.map