summaryrefslogtreecommitdiff
path: root/lib/internal/validators.js
blob: 0ecf286266678afce6069e09b6de050447b7452c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'use strict';

const {
  ERR_INVALID_ARG_TYPE,
  ERR_INVALID_ARG_VALUE,
  ERR_OUT_OF_RANGE
} = require('internal/errors').codes;

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') {
    if (!Number.isInteger(value)) {
      throw new ERR_OUT_OF_RANGE(name, 'an integer', value);
    } else {
      // 2 ** 32 === 4294967296
      throw new ERR_OUT_OF_RANGE(name, '>= 0 && < 4294967296', value);
    }
  }

  if (typeof value === 'string') {
    if (!octalReg.test(value)) {
      throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
    }
    const parsed = parseInt(value, 8);
    return parsed;
  }

  // TODO(BridgeAR): Only return `def` in case `value == null`
  if (def !== undefined) {
    return def;
  }

  throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
}

function validateInteger(value, name) {
  let err;

  if (typeof value !== 'number')
    err = new ERR_INVALID_ARG_TYPE(name, 'number', value);
  else if (!Number.isSafeInteger(value))
    err = new ERR_OUT_OF_RANGE(name, 'an integer', value);

  if (err) {
    Error.captureStackTrace(err, validateInteger);
    throw err;
  }

  return value;
}

function validateInt32(value, name, min = -2147483648, max = 2147483647) {
  // The defaults for min and max correspond to the limits of 32-bit integers.
  if (!isInt32(value)) {
    let err;
    if (typeof value !== 'number') {
      err = new ERR_INVALID_ARG_TYPE(name, 'number', value);
    } else if (!Number.isInteger(value)) {
      err = new ERR_OUT_OF_RANGE(name, 'an integer', value);
    } else {
      err = new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
    }
    Error.captureStackTrace(err, validateInt32);
    throw err;
  } else if (value < min || value > max) {
    const err = new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
    Error.captureStackTrace(err, validateInt32);
    throw err;
  }

  return value;
}

function validateUint32(value, name, positive) {
  if (!isUint32(value)) {
    let err;
    if (typeof value !== 'number') {
      err = new ERR_INVALID_ARG_TYPE(name, 'number', value);
    } else if (!Number.isInteger(value)) {
      err = new ERR_OUT_OF_RANGE(name, 'an integer', value);
    } else {
      const min = positive ? 1 : 0;
      // 2 ** 32 === 4294967296
      err = new ERR_OUT_OF_RANGE(name, `>= ${min} && < 4294967296`, value);
    }
    Error.captureStackTrace(err, validateUint32);
    throw err;
  } else if (positive && value === 0) {
    const err = new ERR_OUT_OF_RANGE(name, '>= 1 && < 4294967296', value);
    Error.captureStackTrace(err, validateUint32);
    throw err;
  }

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