@dwp/govuk-casa
Version:
A framework for building GOVUK Collect-And-Submit-Applications
163 lines • 6.88 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const luxon_1 = require("luxon");
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;
/**
* @typedef {import("../../casa").ErrorMessageConfig} ErrorMessageConfig
* @access private
*/
/**
* @typedef {object} DateObjectConfigOptions
* @property {ErrorMessageConfig} errorMsg Error message config
* @property {object} [afterOffsetFromNow] Offset from now
* @property {ErrorMessageConfig} [errorMsgAfterOffset] Error if date is after
* this offset
* @property {object} [beforeOffsetFromNow] Offset from now
* @property {ErrorMessageConfig} [errorMsgBeforeOffset] Error if date is before
* this offset
* @property {boolean} [allowMonthNames=false] Allow "Jan", "January", etc.
* Default is `false`
* @property {boolean} [allowSingleDigitDay=false] Allow "1" rather than "01".
* Default is `false`
* @property {boolean} [allowSingleDigitMonth=false] Allow "1" rather than "01".
* Default is `false`
* @property {DateTime} [now=false] Override the notion of "now" (useful for
* testing). Default is `false`
*/
/**
* Date object format: { dd: <string>, mm: <string>, yyyy: <string> }.
*
* Note that the time part will be zero'ed, as we are only interested in the
* date component (minimum day resolution).
*
* See {@link DateObjectConfigOptions} for `make()` options.
*
* @memberof Validators
* @augments ValidatorFactory
*/
class DateObject extends ValidatorFactory_js_1.default {
/** @property {string} name Validator name ("dateObject") */
name = "dateObject";
validate(value, dataContext = {}) {
const config = {
errorMsg: {
inline: "validation:rule.dateObject.inline",
summary: "validation:rule.dateObject.summary",
},
errorMsgAfterOffset: {
inline: "validation:rule.dateObject.afterOffset.inline",
summary: "validation:rule.dateObject.afterOffset.summary",
},
errorMsgBeforeOffset: {
inline: "validation:rule.dateObject.beforeOffset.inline",
summary: "validation:rule.dateObject.beforeOffset.summary",
},
now: luxon_1.DateTime.local(),
allowSingleDigitDay: false,
allowSingleDigitMonth: false,
allowMonthNames: false,
afterOffsetFromNow: undefined,
beforeOffsetFromNow: undefined,
...this.config,
};
let valid = false;
let { errorMsg } = config;
let luxonDate;
const NOW = config.now.startOf("day");
// Accepted formats
let formats = ["dd-MM-yyyy"];
const formatTests = [
{
flags: [config.allowSingleDigitDay],
formats: ["d-MM-yyyy"],
},
{
flags: [config.allowSingleDigitDay, config.allowSingleDigitMonth],
formats: ["d-M-yyyy"],
},
{
flags: [config.allowSingleDigitDay, config.allowMonthNames],
formats: ["d-MMM-yyyy", "d-MMMM-yyyy"],
},
{
flags: [config.allowSingleDigitMonth],
formats: ["dd-M-yyyy"],
},
{
flags: [config.allowMonthNames],
formats: ["dd-MMM-yyyy", "dd-MMMM-yyyy"],
},
];
for (const test of formatTests) {
if (test.flags.every((v) => v === true)) {
formats = [...formats, ...test.formats];
}
}
if (typeof value === "object") {
formats.find((format) => {
luxonDate = luxon_1.DateTime.fromFormat([value.dd, value.mm, value.yyyy].join("-"), format).startOf("day");
valid = luxonDate.isValid;
return valid;
});
if (luxonDate) {
// Check date is after the specified duration from now.
// Need to use UTC() otherwise DST shifts can affect the calculated offset
if (config.afterOffsetFromNow) {
const offsetDate = NOW.plus(config.afterOffsetFromNow).startOf("day");
if (luxonDate <= offsetDate) {
valid = false;
errorMsg = config.errorMsgAfterOffset;
}
}
// Check date is before the specified duration from now
// Need to use UTC() otherwise DST shifts can affect the calculated offset
if (config.beforeOffsetFromNow) {
const offsetDate = NOW.plus(config.beforeOffsetFromNow).startOf("day");
if (luxonDate >= offsetDate) {
valid = false;
errorMsg = config.errorMsgBeforeOffset;
}
}
}
// Check presence of each object component (dd, mm, yyyy) in order to log
// which specific parts are in error
errorMsg.focusSuffix = [];
if (!Object.hasOwn(value, "dd") || !value.dd) {
errorMsg.focusSuffix.push("[dd]");
}
if (!Object.hasOwn(value, "mm") || !value.mm) {
errorMsg.focusSuffix.push("[mm]");
}
if (!Object.hasOwn(value, "yyyy") || !value.yyyy) {
errorMsg.focusSuffix.push("[yyyy]");
}
// If the date is invalid, but not specific parts have been highlighted in
// error, then highlight all inputs, focusing on the [dd] first
if (!valid && !errorMsg.focusSuffix.length) {
errorMsg.focusSuffix = ["[dd]", "[mm]", "[yyyy]"];
}
}
return valid ? [] : [ValidationError_js_1.default.make({ errorMsg, dataContext })];
}
sanitise(value) {
if (value !== undefined) {
return isPlainObject(value)
? {
dd: (0, utils_js_1.stripWhitespace)((0, utils_js_1.stringifyInput)(value.dd)),
mm: (0, utils_js_1.stripWhitespace)((0, utils_js_1.stringifyInput)(value.mm)),
yyyy: (0, utils_js_1.stripWhitespace)((0, utils_js_1.stringifyInput)(value.yyyy)),
}
: Object.create(null);
}
return undefined;
}
}
exports.default = DateObject;
//# sourceMappingURL=dateObject.js.map