• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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