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