1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23 24const { 25 ArrayIsArray, 26 Error, 27 NumberIsSafeInteger, 28 ObjectDefineProperties, 29 ObjectDefineProperty, 30 ObjectGetOwnPropertyDescriptors, 31 ObjectKeys, 32 ObjectPrototypeToString, 33 ObjectSetPrototypeOf, 34 ReflectApply, 35} = primordials; 36 37const { 38 codes: { 39 ERR_FALSY_VALUE_REJECTION, 40 ERR_INVALID_ARG_TYPE, 41 ERR_OUT_OF_RANGE 42 }, 43 errnoException, 44 exceptionWithHostPort, 45 hideStackFrames 46} = require('internal/errors'); 47const { 48 format, 49 formatWithOptions, 50 inspect 51} = require('internal/util/inspect'); 52const { debuglog } = require('internal/util/debuglog'); 53const { validateNumber } = require('internal/validators'); 54const { TextDecoder, TextEncoder } = require('internal/encoding'); 55const { isBuffer } = require('buffer').Buffer; 56const types = require('internal/util/types'); 57 58const { 59 deprecate, 60 getSystemErrorName: internalErrorName, 61 promisify 62} = require('internal/util'); 63 64let internalDeepEqual; 65 66function isBoolean(arg) { 67 return typeof arg === 'boolean'; 68} 69 70function isNull(arg) { 71 return arg === null; 72} 73 74function isNullOrUndefined(arg) { 75 return arg === null || arg === undefined; 76} 77 78function isNumber(arg) { 79 return typeof arg === 'number'; 80} 81 82function isString(arg) { 83 return typeof arg === 'string'; 84} 85 86function isSymbol(arg) { 87 return typeof arg === 'symbol'; 88} 89 90function isUndefined(arg) { 91 return arg === undefined; 92} 93 94function isObject(arg) { 95 return arg !== null && typeof arg === 'object'; 96} 97 98function isError(e) { 99 return ObjectPrototypeToString(e) === '[object Error]' || e instanceof Error; 100} 101 102function isFunction(arg) { 103 return typeof arg === 'function'; 104} 105 106function isPrimitive(arg) { 107 return arg === null || 108 (typeof arg !== 'object' && typeof arg !== 'function'); 109} 110 111function pad(n) { 112 return n.toString().padStart(2, '0'); 113} 114 115const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 116 'Oct', 'Nov', 'Dec']; 117 118// 26 Feb 16:19:34 119function timestamp() { 120 const d = new Date(); 121 const time = [pad(d.getHours()), 122 pad(d.getMinutes()), 123 pad(d.getSeconds())].join(':'); 124 return [d.getDate(), months[d.getMonth()], time].join(' '); 125} 126 127let console; 128// Log is just a thin wrapper to console.log that prepends a timestamp 129function log(...args) { 130 if (!console) { 131 console = require('internal/console/global'); 132 } 133 console.log('%s - %s', timestamp(), format(...args)); 134} 135 136/** 137 * Inherit the prototype methods from one constructor into another. 138 * 139 * The Function.prototype.inherits from lang.js rewritten as a standalone 140 * function (not on Function.prototype). NOTE: If this file is to be loaded 141 * during bootstrapping this function needs to be rewritten using some native 142 * functions as prototype setup using normal JavaScript does not work as 143 * expected during bootstrapping (see mirror.js in r114903). 144 * 145 * @param {function} ctor Constructor function which needs to inherit the 146 * prototype. 147 * @param {function} superCtor Constructor function to inherit prototype from. 148 * @throws {TypeError} Will error if either constructor is null, or if 149 * the super constructor lacks a prototype. 150 */ 151function inherits(ctor, superCtor) { 152 153 if (ctor === undefined || ctor === null) 154 throw new ERR_INVALID_ARG_TYPE('ctor', 'Function', ctor); 155 156 if (superCtor === undefined || superCtor === null) 157 throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor); 158 159 if (superCtor.prototype === undefined) { 160 throw new ERR_INVALID_ARG_TYPE('superCtor.prototype', 161 'Object', superCtor.prototype); 162 } 163 ObjectDefineProperty(ctor, 'super_', { 164 value: superCtor, 165 writable: true, 166 configurable: true 167 }); 168 ObjectSetPrototypeOf(ctor.prototype, superCtor.prototype); 169} 170 171function _extend(target, source) { 172 // Don't do anything if source isn't an object 173 if (source === null || typeof source !== 'object') return target; 174 175 const keys = ObjectKeys(source); 176 let i = keys.length; 177 while (i--) { 178 target[keys[i]] = source[keys[i]]; 179 } 180 return target; 181} 182 183const callbackifyOnRejected = hideStackFrames((reason, cb) => { 184 // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). 185 // Because `null` is a special error value in callbacks which means "no error 186 // occurred", we error-wrap so the callback consumer can distinguish between 187 // "the promise rejected with null" or "the promise fulfilled with undefined". 188 if (!reason) { 189 reason = new ERR_FALSY_VALUE_REJECTION(reason); 190 } 191 return cb(reason); 192}); 193 194function callbackify(original) { 195 if (typeof original !== 'function') { 196 throw new ERR_INVALID_ARG_TYPE('original', 'Function', original); 197 } 198 199 // We DO NOT return the promise as it gives the user a false sense that 200 // the promise is actually somehow related to the callback's execution 201 // and that the callback throwing will reject the promise. 202 function callbackified(...args) { 203 const maybeCb = args.pop(); 204 if (typeof maybeCb !== 'function') { 205 throw new ERR_INVALID_ARG_TYPE('last argument', 'Function', maybeCb); 206 } 207 const cb = (...args) => { ReflectApply(maybeCb, this, args); }; 208 // In true node style we process the callback on `nextTick` with all the 209 // implications (stack, `uncaughtException`, `async_hooks`) 210 ReflectApply(original, this, args) 211 .then((ret) => process.nextTick(cb, null, ret), 212 (rej) => process.nextTick(callbackifyOnRejected, rej, cb)); 213 } 214 215 const descriptors = ObjectGetOwnPropertyDescriptors(original); 216 // It is possible to manipulate a functions `length` or `name` property. This 217 // guards against the manipulation. 218 if (typeof descriptors.length.value === 'number') { 219 descriptors.length.value++; 220 } 221 if (typeof descriptors.name.value === 'string') { 222 descriptors.name.value += 'Callbackified'; 223 } 224 ObjectDefineProperties(callbackified, descriptors); 225 return callbackified; 226} 227 228function getSystemErrorName(err) { 229 validateNumber(err, 'err'); 230 if (err >= 0 || !NumberIsSafeInteger(err)) { 231 throw new ERR_OUT_OF_RANGE('err', 'a negative integer', err); 232 } 233 return internalErrorName(err); 234} 235 236// Keep the `exports =` so that various functions can still be monkeypatched 237module.exports = { 238 _errnoException: errnoException, 239 _exceptionWithHostPort: exceptionWithHostPort, 240 _extend, 241 callbackify, 242 debuglog, 243 deprecate, 244 format, 245 formatWithOptions, 246 getSystemErrorName, 247 inherits, 248 inspect, 249 isArray: ArrayIsArray, 250 isBoolean, 251 isBuffer, 252 isDeepStrictEqual(a, b) { 253 if (internalDeepEqual === undefined) { 254 internalDeepEqual = require('internal/util/comparisons') 255 .isDeepStrictEqual; 256 } 257 return internalDeepEqual(a, b); 258 }, 259 isNull, 260 isNullOrUndefined, 261 isNumber, 262 isString, 263 isSymbol, 264 isUndefined, 265 isRegExp: types.isRegExp, 266 isObject, 267 isDate: types.isDate, 268 isError, 269 isFunction, 270 isPrimitive, 271 log, 272 promisify, 273 TextDecoder, 274 TextEncoder, 275 types 276}; 277