1'use strict'; 2 3const { 4 MathAbs, 5 MathMax, 6 MathMin, 7 MathPow, 8 MathSign, 9 MathTrunc, 10 NumberIsNaN, 11 NumberMAX_SAFE_INTEGER, 12 NumberMIN_SAFE_INTEGER, 13 String, 14} = primordials; 15 16const { 17 codes: { 18 ERR_INVALID_ARG_VALUE, 19 }, 20} = require('internal/errors'); 21const { kEmptyObject } = require('internal/util'); 22 23const converters = { __proto__: null }; 24 25// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart 26const integerPart = MathTrunc; 27 28/* eslint-disable node-core/non-ascii-character */ 29// Round x to the nearest integer, choosing the even integer if it lies halfway 30// between two, and choosing +0 rather than -0. 31// This is different from Math.round, which rounds to the next integer in the 32// direction of +∞ when the fraction portion is exactly 0.5. 33/* eslint-enable node-core/non-ascii-character */ 34function evenRound(x) { 35 // Convert -0 to +0. 36 const i = integerPart(x) + 0; 37 const reminder = MathAbs(x % 1); 38 const sign = MathSign(i); 39 if (reminder === 0.5) { 40 return i % 2 === 0 ? i : i + sign; 41 } 42 const r = reminder < 0.5 ? i : i + sign; 43 // Convert -0 to +0. 44 if (r === 0) { 45 return 0; 46 } 47 return r; 48} 49 50function pow2(exponent) { 51 // << operates on 32 bit signed integers. 52 if (exponent < 31) { 53 return 1 << exponent; 54 } 55 if (exponent === 31) { 56 return 0x8000_0000; 57 } 58 if (exponent === 32) { 59 return 0x1_0000_0000; 60 } 61 return MathPow(2, exponent); 62} 63 64// https://tc39.es/ecma262/#eqn-modulo 65// The notation “x modulo y” computes a value k of the same sign as y. 66function modulo(x, y) { 67 const r = x % y; 68 // Convert -0 to +0. 69 if (r === 0) { 70 return 0; 71 } 72 return r; 73} 74 75// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint 76function convertToInt(name, value, bitLength, options = kEmptyObject) { 77 const { signed = false, enforceRange = false, clamp = false } = options; 78 79 let upperBound; 80 let lowerBound; 81 // 1. If bitLength is 64, then: 82 if (bitLength === 64) { 83 // 1.1. Let upperBound be 2^53 − 1. 84 upperBound = NumberMAX_SAFE_INTEGER; 85 // 1.2. If signedness is "unsigned", then let lowerBound be 0. 86 // 1.3. Otherwise let lowerBound be −2^53 + 1. 87 lowerBound = !signed ? 0 : NumberMIN_SAFE_INTEGER; 88 } else if (!signed) { 89 // 2. Otherwise, if signedness is "unsigned", then: 90 // 2.1. Let lowerBound be 0. 91 // 2.2. Let upperBound be 2^bitLength − 1. 92 lowerBound = 0; 93 upperBound = pow2(bitLength) - 1; 94 } else { 95 // 3. Otherwise: 96 // 3.1. Let lowerBound be -2^(bitLength − 1). 97 // 3.2. Let upperBound be 2^(bitLength − 1) − 1. 98 lowerBound = -pow2(bitLength - 1); 99 upperBound = pow2(bitLength - 1) - 1; 100 } 101 102 // 4. Let x be ? ToNumber(V). 103 let x = +value; 104 // 5. If x is −0, then set x to +0. 105 if (x === 0) { 106 x = 0; 107 } 108 109 // 6. If the conversion is to an IDL type associated with the [EnforceRange] 110 // extended attribute, then: 111 if (enforceRange) { 112 // 6.1. If x is NaN, +∞, or −∞, then throw a TypeError. 113 if (NumberIsNaN(x) || x === Infinity || x === -Infinity) { 114 throw new ERR_INVALID_ARG_VALUE(name, x); 115 } 116 // 6.2. Set x to IntegerPart(x). 117 x = integerPart(x); 118 119 // 6.3. If x < lowerBound or x > upperBound, then throw a TypeError. 120 if (x < lowerBound || x > upperBound) { 121 throw new ERR_INVALID_ARG_VALUE(name, x); 122 } 123 124 // 6.4. Return x. 125 return x; 126 } 127 128 // 7. If x is not NaN and the conversion is to an IDL type associated with 129 // the [Clamp] extended attribute, then: 130 if (clamp && !NumberIsNaN(x)) { 131 // 7.1. Set x to min(max(x, lowerBound), upperBound). 132 x = MathMin(MathMax(x, lowerBound), upperBound); 133 134 // 7.2. Round x to the nearest integer, choosing the even integer if it 135 // lies halfway between two, and choosing +0 rather than −0. 136 x = evenRound(x); 137 138 // 7.3. Return x. 139 return x; 140 } 141 142 // 8. If x is NaN, +0, +∞, or −∞, then return +0. 143 if (NumberIsNaN(x) || x === 0 || x === Infinity || x === -Infinity) { 144 return 0; 145 } 146 147 // 9. Set x to IntegerPart(x). 148 x = integerPart(x); 149 150 // 10. Set x to x modulo 2^bitLength. 151 x = modulo(x, pow2(bitLength)); 152 153 // 11. If signedness is "signed" and x ≥ 2^(bitLength − 1), then return x − 154 // 2^bitLength. 155 if (signed && x >= pow2(bitLength - 1)) { 156 return x - pow2(bitLength); 157 } 158 159 // 12. Otherwise, return x. 160 return x; 161} 162 163/** 164 * @see https://webidl.spec.whatwg.org/#es-DOMString 165 * @param {any} V 166 * @returns {string} 167 */ 168converters.DOMString = function DOMString(V) { 169 if (typeof V === 'symbol') { 170 throw new ERR_INVALID_ARG_VALUE('value', V); 171 } 172 173 return String(V); 174}; 175 176module.exports = { 177 convertToInt, 178 evenRound, 179 converters, 180}; 181