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