You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					190 lines
				
				4.9 KiB
			
		
		
			
		
	
	
					190 lines
				
				4.9 KiB
			| 
											3 years ago
										 | "use strict"; | ||
|  | 
 | ||
|  | var conversions = {}; | ||
|  | module.exports = conversions; | ||
|  | 
 | ||
|  | function sign(x) { | ||
|  |     return x < 0 ? -1 : 1; | ||
|  | } | ||
|  | 
 | ||
|  | function evenRound(x) { | ||
|  |     // Round x to the nearest integer, choosing the even integer if it lies halfway between two.
 | ||
|  |     if ((x % 1) === 0.5 && (x & 1) === 0) { // [even number].5; round down (i.e. floor)
 | ||
|  |         return Math.floor(x); | ||
|  |     } else { | ||
|  |         return Math.round(x); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | function createNumberConversion(bitLength, typeOpts) { | ||
|  |     if (!typeOpts.unsigned) { | ||
|  |         --bitLength; | ||
|  |     } | ||
|  |     const lowerBound = typeOpts.unsigned ? 0 : -Math.pow(2, bitLength); | ||
|  |     const upperBound = Math.pow(2, bitLength) - 1; | ||
|  | 
 | ||
|  |     const moduloVal = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength) : Math.pow(2, bitLength); | ||
|  |     const moduloBound = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength - 1) : Math.pow(2, bitLength - 1); | ||
|  | 
 | ||
|  |     return function(V, opts) { | ||
|  |         if (!opts) opts = {}; | ||
|  | 
 | ||
|  |         let x = +V; | ||
|  | 
 | ||
|  |         if (opts.enforceRange) { | ||
|  |             if (!Number.isFinite(x)) { | ||
|  |                 throw new TypeError("Argument is not a finite number"); | ||
|  |             } | ||
|  | 
 | ||
|  |             x = sign(x) * Math.floor(Math.abs(x)); | ||
|  |             if (x < lowerBound || x > upperBound) { | ||
|  |                 throw new TypeError("Argument is not in byte range"); | ||
|  |             } | ||
|  | 
 | ||
|  |             return x; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (!isNaN(x) && opts.clamp) { | ||
|  |             x = evenRound(x); | ||
|  | 
 | ||
|  |             if (x < lowerBound) x = lowerBound; | ||
|  |             if (x > upperBound) x = upperBound; | ||
|  |             return x; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (!Number.isFinite(x) || x === 0) { | ||
|  |             return 0; | ||
|  |         } | ||
|  | 
 | ||
|  |         x = sign(x) * Math.floor(Math.abs(x)); | ||
|  |         x = x % moduloVal; | ||
|  | 
 | ||
|  |         if (!typeOpts.unsigned && x >= moduloBound) { | ||
|  |             return x - moduloVal; | ||
|  |         } else if (typeOpts.unsigned) { | ||
|  |             if (x < 0) { | ||
|  |               x += moduloVal; | ||
|  |             } else if (x === -0) { // don't return negative zero
 | ||
|  |               return 0; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return x; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | conversions["void"] = function () { | ||
|  |     return undefined; | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["boolean"] = function (val) { | ||
|  |     return !!val; | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["byte"] = createNumberConversion(8, { unsigned: false }); | ||
|  | conversions["octet"] = createNumberConversion(8, { unsigned: true }); | ||
|  | 
 | ||
|  | conversions["short"] = createNumberConversion(16, { unsigned: false }); | ||
|  | conversions["unsigned short"] = createNumberConversion(16, { unsigned: true }); | ||
|  | 
 | ||
|  | conversions["long"] = createNumberConversion(32, { unsigned: false }); | ||
|  | conversions["unsigned long"] = createNumberConversion(32, { unsigned: true }); | ||
|  | 
 | ||
|  | conversions["long long"] = createNumberConversion(32, { unsigned: false, moduloBitLength: 64 }); | ||
|  | conversions["unsigned long long"] = createNumberConversion(32, { unsigned: true, moduloBitLength: 64 }); | ||
|  | 
 | ||
|  | conversions["double"] = function (V) { | ||
|  |     const x = +V; | ||
|  | 
 | ||
|  |     if (!Number.isFinite(x)) { | ||
|  |         throw new TypeError("Argument is not a finite floating-point value"); | ||
|  |     } | ||
|  | 
 | ||
|  |     return x; | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["unrestricted double"] = function (V) { | ||
|  |     const x = +V; | ||
|  | 
 | ||
|  |     if (isNaN(x)) { | ||
|  |         throw new TypeError("Argument is NaN"); | ||
|  |     } | ||
|  | 
 | ||
|  |     return x; | ||
|  | }; | ||
|  | 
 | ||
|  | // not quite valid, but good enough for JS
 | ||
|  | conversions["float"] = conversions["double"]; | ||
|  | conversions["unrestricted float"] = conversions["unrestricted double"]; | ||
|  | 
 | ||
|  | conversions["DOMString"] = function (V, opts) { | ||
|  |     if (!opts) opts = {}; | ||
|  | 
 | ||
|  |     if (opts.treatNullAsEmptyString && V === null) { | ||
|  |         return ""; | ||
|  |     } | ||
|  | 
 | ||
|  |     return String(V); | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["ByteString"] = function (V, opts) { | ||
|  |     const x = String(V); | ||
|  |     let c = undefined; | ||
|  |     for (let i = 0; (c = x.codePointAt(i)) !== undefined; ++i) { | ||
|  |         if (c > 255) { | ||
|  |             throw new TypeError("Argument is not a valid bytestring"); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return x; | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["USVString"] = function (V) { | ||
|  |     const S = String(V); | ||
|  |     const n = S.length; | ||
|  |     const U = []; | ||
|  |     for (let i = 0; i < n; ++i) { | ||
|  |         const c = S.charCodeAt(i); | ||
|  |         if (c < 0xD800 || c > 0xDFFF) { | ||
|  |             U.push(String.fromCodePoint(c)); | ||
|  |         } else if (0xDC00 <= c && c <= 0xDFFF) { | ||
|  |             U.push(String.fromCodePoint(0xFFFD)); | ||
|  |         } else { | ||
|  |             if (i === n - 1) { | ||
|  |                 U.push(String.fromCodePoint(0xFFFD)); | ||
|  |             } else { | ||
|  |                 const d = S.charCodeAt(i + 1); | ||
|  |                 if (0xDC00 <= d && d <= 0xDFFF) { | ||
|  |                     const a = c & 0x3FF; | ||
|  |                     const b = d & 0x3FF; | ||
|  |                     U.push(String.fromCodePoint((2 << 15) + (2 << 9) * a + b)); | ||
|  |                     ++i; | ||
|  |                 } else { | ||
|  |                     U.push(String.fromCodePoint(0xFFFD)); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return U.join(''); | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["Date"] = function (V, opts) { | ||
|  |     if (!(V instanceof Date)) { | ||
|  |         throw new TypeError("Argument is not a Date object"); | ||
|  |     } | ||
|  |     if (isNaN(V)) { | ||
|  |         return undefined; | ||
|  |     } | ||
|  | 
 | ||
|  |     return V; | ||
|  | }; | ||
|  | 
 | ||
|  | conversions["RegExp"] = function (V, opts) { | ||
|  |     if (!(V instanceof RegExp)) { | ||
|  |         V = new RegExp(V); | ||
|  |     } | ||
|  | 
 | ||
|  |     return V; | ||
|  | }; |