Source: schema/validateSchema.js

/**
 * @module validateSchema
 */
const compareDates = require('../util/compareDates');
const isType = require('../util/isType');

/**
 * @constant
 * @type {Map}
 * @name monthDays
 * @description Map of Days in a Month based on Year
 */
const monthDays = new Map([
    [1, (_) => 31],
    [2, (year) => year % 4 === 0 ? 29 : 28],
    [3, (_) => 31],
    [4, (_) => 30],
    [5, (_) => 31],
    [6, (_) => 30],
    [7, (_) => 31],
    [8, (_) => 31],
    [9, (_) => 30],
    [10, (_) => 31],
    [11, (_) => 30],
    [12, (_) => 31]
]);

/**
 * @function
 * @name validateSchema
 * @description Validates Input against AdventSchema
 * @param {*} input Input Argument
 * @returns {(Object|false)} Value of Input if Valid, false otherwise
 */
function validateSchema(input) {

    if (!isType.isObject(input)) {
        return false;
    }

    const value = {};

    // start
    const start = validateDate(input.start);
    if (start) {
        value.start = start;
    } else {
        return false;
    }

    // end?
    const end = validateDate(input.end);
    if (end) {
        if (compareDates(start, end) <= 0) {
            value.end = end;
        } else {
            return false;
        }
    } else {
        value.end = null;
    }

    // title
    const title = input.title;
    if (isType.isString(title)) {
        value.title = title;
    } else {
        return false;
    }

    // content
    const content = input.content;
    if (isType.isString(content)) {
        value.content = content;
    } else {
        return false;
    }

    // tags
    const tags = validateTags(input.tags);
    if (tags) {
        value.tags = tags;
    } else {
        return false;
    }

    return value;
}

/**
 * @function
 * @name validateDate
 * @description Validates Input against DateSchema
 * @param {*} input Input Argument
 * @returns {(Object|false)} Value of Input if Valid, false otherwise
 */
function validateDate(input) {

    if (!isType.isObject(input)) {
        return false;
    }

    const value = {};

    // Year
    if (isType.isNumber(input.year) &&
        (1 <= input.year)) {
        value.year = input.year;
    } else {
        return false;
    }

    // Month
    if (isType.isNumber(input.month) &&
        (1 <= input.month && input.month <= 12)) {
        value.month = input.month;
    } else {
        value.month = null;
    }

    // Day
    if (isType.isNumber(input.day)) {
        if (!isType.isNull(value.month) &&
            (1 <= input.day && input.day <= monthDays.get(value.month)(value.year))) {
            value.day = input.day;
        } else {
            return false;
        }
    } else {
        value.day = null;
    }

    // Fill out nulls
    if (value.month === null) {
        value.month = 1;
    }
    if (value.day === null) {
        value.day = 1;
    }

    return value;
}

/**
 * @function
 * @name validateTags
 * @description Validates Input against AdventSchema.tags
 * @param {*} input Input Argument
 * @returns {(Object|false)} Value of Input if Valid, false otherwise
 */
function validateTags(input) {

    if (!Array.isArray(input)) {
        return false;
    }

    if (input.some(tag => !isType.isString(tag))) {
        return false;
    }

    return input;
}

module.exports = validateSchema;