You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
2.3 KiB
JavaScript

"use strict";
const defaultValue = require("default-value");
const escapeStringRegexp = require("escape-string-regexp");
const isString = require("@validatem/is-string");
const matchesFormat = require("@validatem/matches-format");
const wrapError = require("@validatem/wrap-error");
function replaceAll(string, search, replace) {
let regex = new RegExp(escapeStringRegexp(search), "g");
return string.replace(regex, replace);
}
function generateRequirementsList(requirements) {
return Object.entries(requirements)
.filter(([ _key, value ]) => value === true)
.map(([ key, _value]) => key);
}
module.exports = function makeIsNumericValidator(options = {}) {
let decimalSeparator = defaultValue(options.decimalSeparator, ".");
let groupSeparator = defaultValue(options.groupSeparator, ",");
let allowDecimal = defaultValue(options.allowDecimal, false);
let allowGroups = defaultValue(options.allowGroups, false);
let allowNegative = defaultValue(options.allowNegative, false);
let parse = defaultValue(options.parse, false);
function parseNumber(value, context) {
// Automatically avoid parsing if `ignoreResult` has been used
if (context.parseIntoResult !== false) {
let strippedValue = (allowGroups)
? replaceAll(value, groupSeparator, "")
: value;
let normalizedValue = (decimalSeparator !== ".")
? replaceAll(strippedValue, decimalSeparator, ".")
: strippedValue;
if (allowDecimal) {
return parseFloat(normalizedValue);
} else {
return parseInt(normalizedValue);
}
}
}
let integerPartRegex = (allowGroups)
? `\\d+(${escapeStringRegexp(groupSeparator)}\\d+)*`
: "\\d+";
let negativePrefixRegex = (allowNegative)
? "-?"
: "";
let fractionalPartRegex = (allowDecimal)
? `(${escapeStringRegexp(decimalSeparator)}\\d+)?`
: "";
let parser = (parse)
? parseNumber
: undefined;
let requirements = generateRequirementsList({
"whole": !allowDecimal,
"positive": !allowNegative,
"ungrouped": !allowGroups
});
let requirementsString = (requirements.length > 0)
? `string representing a ${requirements.join(", ")} number`
: "numeric string";
return wrapError(`Must be a ${requirementsString}`, [
isString,
matchesFormat(new RegExp(`^${negativePrefixRegex}${integerPartRegex}${fractionalPartRegex}$`)),
parser
]);
};