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
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
|
|
]);
|
|
};
|