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