node/lib/internal/validators.js
Ruben Bridgewater bfbce289c3
lib: refactor Error.captureStackTrace() usage
When using `Errors.captureStackFrames` the error's stack property
is set again. This adds a helper function that wraps this functionality
in a simple API that does not only set the stack including the `code`
property but it also improves the performance to create the error.
The helper works for thrown errors and errors returned from wrapped
functions in case they are Node.js core errors.

PR-URL: https://github.com/nodejs/node/pull/26738
Fixes: https://github.com/nodejs/node/issues/26669
Fixes: https://github.com/nodejs/node/issues/20253
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2019-03-23 02:55:54 +01:00

125 lines
3.3 KiB
JavaScript

'use strict';
const {
hideStackFrames,
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_OUT_OF_RANGE
}
} = require('internal/errors');
function isInt32(value) {
return value === (value | 0);
}
function isUint32(value) {
return value === (value >>> 0);
}
const octalReg = /^[0-7]+$/;
const modeDesc = 'must be a 32-bit unsigned integer or an octal string';
/**
* Validate values that will be converted into mode_t (the S_* constants).
* Only valid numbers and octal strings are allowed. They could be converted
* to 32-bit unsigned integers or non-negative signed integers in the C++
* land, but any value higher than 0o777 will result in platform-specific
* behaviors.
*
* @param {*} value Values to be validated
* @param {string} name Name of the argument
* @param {number} def If specified, will be returned for invalid values
* @returns {number}
*/
function validateMode(value, name, def) {
if (isUint32(value)) {
return value;
}
if (typeof value === 'number') {
validateInt32(value, name, 0, 2 ** 32 - 1);
}
if (typeof value === 'string') {
if (!octalReg.test(value)) {
throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
}
return parseInt(value, 8);
}
if (def !== undefined && value == null) {
return def;
}
throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
}
const validateInteger = hideStackFrames((value, name) => {
if (typeof value !== 'number')
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
if (!Number.isSafeInteger(value))
throw new ERR_OUT_OF_RANGE(name, 'an integer', value);
return value;
});
const validateInt32 = hideStackFrames(
(value, name, min = -2147483648, max = 2147483647) => {
// The defaults for min and max correspond to the limits of 32-bit integers.
if (!isInt32(value)) {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
}
if (!Number.isInteger(value)) {
throw new ERR_OUT_OF_RANGE(name, 'an integer', value);
}
throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
}
if (value < min || value > max) {
throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
}
return value;
}
);
const validateUint32 = hideStackFrames((value, name, positive) => {
if (!isUint32(value)) {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
}
if (!Number.isInteger(value)) {
throw new ERR_OUT_OF_RANGE(name, 'an integer', value);
}
const min = positive ? 1 : 0;
// 2 ** 32 === 4294967296
throw new ERR_OUT_OF_RANGE(name, `>= ${min} && < 4294967296`, value);
}
if (positive && value === 0) {
throw new ERR_OUT_OF_RANGE(name, '>= 1 && < 4294967296', value);
}
// TODO(BridgeAR): Remove return values from validation functions and
// especially reduce side effects caused by validation functions.
return value;
});
function validateString(value, name) {
if (typeof value !== 'string')
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
}
function validateNumber(value, name) {
if (typeof value !== 'number')
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
}
module.exports = {
isInt32,
isUint32,
validateMode,
validateInteger,
validateInt32,
validateUint32,
validateString,
validateNumber
};