• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  ArrayIsArray,
5  Error,
6} = primordials;
7
8const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
9
10// Lazily loaded
11let fs;
12let fd;
13let warningFile;
14let options;
15
16function lazyOption() {
17  // This will load `warningFile` only once. If the flag is not set,
18  // `warningFile` will be set to an empty string.
19  if (warningFile === undefined) {
20    options = require('internal/options');
21    if (options.getOptionValue('--diagnostic-dir') !== '') {
22      warningFile = options.getOptionValue('--diagnostic-dir');
23    }
24    if (options.getOptionValue('--redirect-warnings') !== '') {
25      warningFile = options.getOptionValue('--redirect-warnings');
26    } else {
27      warningFile = '';
28    }
29  }
30  return warningFile;
31}
32
33// If we can't write to stderr, we'd like to make this a noop,
34// so use console.error.
35let error;
36function writeOut(message) {
37  if (!error) {
38    error = require('internal/console/global').error;
39  }
40  error(message);
41}
42
43function writeToFile(message) {
44  if (fd === undefined) {
45    fs = require('fs');
46    try {
47      fd = fs.openSync(warningFile, 'a');
48    } catch {
49      return writeOut(message);
50    }
51    process.on('exit', () => {
52      try {
53        fs.closeSync(fd);
54      } catch {}
55    });
56  }
57  fs.appendFile(fd, `${message}\n`, (err) => {
58    if (err) {
59      writeOut(message);
60    }
61  });
62}
63
64function doEmitWarning(warning) {
65  return () => process.emit('warning', warning);
66}
67
68function onWarning(warning) {
69  if (!(warning instanceof Error)) return;
70  const isDeprecation = warning.name === 'DeprecationWarning';
71  if (isDeprecation && process.noDeprecation) return;
72  const trace = process.traceProcessWarnings ||
73                (isDeprecation && process.traceDeprecation);
74  let msg = `(${process.release.name}:${process.pid}) `;
75  if (warning.code)
76    msg += `[${warning.code}] `;
77  if (trace && warning.stack) {
78    msg += `${warning.stack}`;
79  } else {
80    const toString =
81      typeof warning.toString === 'function' ?
82        warning.toString : Error.prototype.toString;
83    msg += `${toString.apply(warning)}`;
84  }
85  if (typeof warning.detail === 'string') {
86    msg += `\n${warning.detail}`;
87  }
88  const warningFile = lazyOption();
89  if (warningFile) {
90    return writeToFile(msg);
91  }
92  writeOut(msg);
93}
94
95// process.emitWarning(error)
96// process.emitWarning(str[, type[, code]][, ctor])
97// process.emitWarning(str[, options])
98function emitWarning(warning, type, code, ctor, now) {
99  let detail;
100  if (type !== null && typeof type === 'object' && !ArrayIsArray(type)) {
101    ctor = type.ctor;
102    code = type.code;
103    if (typeof type.detail === 'string')
104      detail = type.detail;
105    type = type.type || 'Warning';
106  } else if (typeof type === 'function') {
107    ctor = type;
108    code = undefined;
109    type = 'Warning';
110  }
111  if (type !== undefined && typeof type !== 'string') {
112    throw new ERR_INVALID_ARG_TYPE('type', 'string', type);
113  }
114  if (typeof code === 'function') {
115    ctor = code;
116    code = undefined;
117  } else if (code !== undefined && typeof code !== 'string') {
118    throw new ERR_INVALID_ARG_TYPE('code', 'string', code);
119  }
120  if (typeof warning === 'string') {
121    // Improve error creation performance by skipping the error frames.
122    // They are added in the `captureStackTrace()` function below.
123    const tmpStackLimit = Error.stackTraceLimit;
124    Error.stackTraceLimit = 0;
125    // eslint-disable-next-line no-restricted-syntax
126    warning = new Error(warning);
127    Error.stackTraceLimit = tmpStackLimit;
128    warning.name = String(type || 'Warning');
129    if (code !== undefined) warning.code = code;
130    if (detail !== undefined) warning.detail = detail;
131    // eslint-disable-next-line no-restricted-syntax
132    Error.captureStackTrace(warning, ctor || process.emitWarning);
133  } else if (!(warning instanceof Error)) {
134    throw new ERR_INVALID_ARG_TYPE('warning', ['Error', 'string'], warning);
135  }
136  if (warning.name === 'DeprecationWarning') {
137    if (process.noDeprecation)
138      return;
139    if (process.throwDeprecation)
140      throw warning;
141  }
142  if (now) process.emit('warning', warning);
143  else process.nextTick(doEmitWarning(warning));
144}
145
146module.exports = {
147  onWarning,
148  emitWarning
149};
150