Skip to content

Commit

Permalink
process: add optional code to warnings + type checking
Browse files Browse the repository at this point in the history
Add the ability to assign an optional code to process warnings +
add additional type checking to ensure that names and codes can
only be strings.

PR-URL: #10116
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Michal Zasso <targos@protonmail.com>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
  • Loading branch information
jasnell committed Jan 30, 2017
1 parent 60d77bd commit 5e1f32f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 22 deletions.
25 changes: 17 additions & 8 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,15 @@ console.log(process.env.test);
// => 1
```

## process.emitWarning(warning[, name][, ctor])
## process.emitWarning(warning[, type[, code]][, ctor])
<!-- YAML
added: v6.0.0
-->

* `warning` {String | Error} The warning to emit.
* `name` {String} When `warning` is a String, `name` is the name to use
for the warning. Default: `Warning`.
* `type` {String} When `warning` is a String, `type` is the name to use
for the *type* of warning being emitted. Default: `Warning`.
* `code` {String} A unique identifier for the warning instance being emitted.
* `ctor` {Function} When `warning` is a String, `ctor` is an optional
function used to limit the generated stack trace. Default
`process.emitWarning`
Expand All @@ -729,11 +730,16 @@ process.emitWarning('Something happened!');
```

```js
// Emit a warning using a string and a name...
// Emit a warning using a string and a type...
process.emitWarning('Something Happened!', 'CustomWarning');
// Emits: (node:56338) CustomWarning: Something Happened!
```

```js
process.emitWarning('Something happened!', 'CustomWarning', 'WARN001');
// Emits: (node:56338) CustomWarning [WARN001]: Something Happened!
```

In each of the previous examples, an `Error` object is generated internally by
`process.emitWarning()` and passed through to the
[`process.on('warning')`][process_warning] event.
Expand All @@ -742,21 +748,24 @@ In each of the previous examples, an `Error` object is generated internally by
process.on('warning', (warning) => {
console.warn(warning.name);
console.warn(warning.message);
console.warn(warning.code);
console.warn(warning.stack);
});
```

If `warning` is passed as an `Error` object, it will be passed through to the
`process.on('warning')` event handler unmodified (and the optional `name`
and `ctor` arguments will be ignored):
`process.on('warning')` event handler unmodified (and the optional `type`,
`code` and `ctor` arguments will be ignored):

```js
// Emit a warning using an Error object...
const myWarning = new Error('Warning! Something happened!');
// Use the Error name property to specify the type name
myWarning.name = 'CustomWarning';
myWarning.code = 'WARN001';

process.emitWarning(myWarning);
// Emits: (node:56338) CustomWarning: Warning! Something Happened!
// Emits: (node:56338) CustomWarning [WARN001]: Warning! Something Happened!
```

A `TypeError` is thrown if `warning` is anything other than a string or `Error`
Expand All @@ -765,7 +774,7 @@ object.
Note that while process warnings use `Error` objects, the process warning
mechanism is **not** a replacement for normal error handling mechanisms.

The following additional handling is implemented if the warning `name` is
The following additional handling is implemented if the warning `type` is
`DeprecationWarning`:

* If the `--throw-deprecation` command-line flag is used, the deprecation
Expand Down
41 changes: 30 additions & 11 deletions lib/internal/process/warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,45 @@ function setupProcessWarnings() {
const trace = process.traceProcessWarnings ||
(isDeprecation && process.traceDeprecation);
if (trace && warning.stack) {
console.error(`${prefix}${warning.stack}`);
if (warning.code) {
console.error(`${prefix}[${warning.code}] ${warning.stack}`);
} else {
console.error(`${prefix}${warning.stack}`);
}
} else {
var toString = warning.toString;
if (typeof toString !== 'function')
toString = Error.prototype.toString;
console.error(`${prefix}${toString.apply(warning)}`);
const toString =
typeof warning.toString === 'function' ?
warning.toString : Error.prototype.toString;
if (warning.code) {
console.error(
`${prefix}[${warning.code}] ${toString.apply(warning)}`);
} else {
console.error(`${prefix}${toString.apply(warning)}`);
}
}
});
}

// process.emitWarning(error)
// process.emitWarning(str[, name][, ctor])
process.emitWarning = function(warning, name, ctor) {
if (typeof name === 'function') {
ctor = name;
name = 'Warning';
// process.emitWarning(str[, type[, code]][, ctor])
process.emitWarning = function(warning, type, code, ctor) {
if (typeof type === 'function') {
ctor = type;
code = undefined;
type = 'Warning';
}
if (typeof code === 'function') {
ctor = code;
code = undefined;
}
if (code !== undefined && typeof code !== 'string')
throw new TypeError('\'code\' must be a String');
if (type !== undefined && typeof type !== 'string')
throw new TypeError('\'type\' must be a String');
if (warning === undefined || typeof warning === 'string') {
warning = new Error(warning);
warning.name = name || 'Warning';
warning.name = String(type || 'Warning');
if (code !== undefined) warning.code = code;
Error.captureStackTrace(warning, ctor || process.emitWarning);
}
if (!(warning instanceof Error)) {
Expand Down
19 changes: 16 additions & 3 deletions test/parallel/test-process-emitwarning.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ const util = require('util');
process.on('warning', common.mustCall((warning) => {
assert(warning);
assert(/^(Warning|CustomWarning)/.test(warning.name));
assert(warning.message, 'A Warning');
}, 7));
assert.strictEqual(warning.message, 'A Warning');
if (warning.code) assert.strictEqual(warning.code, 'CODE001');
}, 8));

process.emitWarning('A Warning');
process.emitWarning('A Warning', 'CustomWarning');
process.emitWarning('A Warning', CustomWarning);
process.emitWarning('A Warning', 'CustomWarning', CustomWarning);
process.emitWarning('A Warning', 'CustomWarning', 'CODE001');

function CustomWarning() {
Error.call(this);
this.name = 'CustomWarning';
this.message = 'A Warning';
this.code = 'CODE001';
Error.captureStackTrace(this, CustomWarning);
}
util.inherits(CustomWarning, Error);
Expand All @@ -36,6 +39,16 @@ warningThrowToString.toString = function() {
};
process.emitWarning(warningThrowToString);

// TypeError is thrown on invalid output
// TypeError is thrown on invalid input
assert.throws(() => process.emitWarning(1), TypeError);
assert.throws(() => process.emitWarning({}), TypeError);
assert.throws(() => process.emitWarning(true), TypeError);
assert.throws(() => process.emitWarning([]), TypeError);
assert.throws(() => process.emitWarning('', {}), TypeError);
assert.throws(() => process.emitWarning('', '', {}), TypeError);
assert.throws(() => process.emitWarning('', 1), TypeError);
assert.throws(() => process.emitWarning('', '', 1), TypeError);
assert.throws(() => process.emitWarning('', true), TypeError);
assert.throws(() => process.emitWarning('', '', true), TypeError);
assert.throws(() => process.emitWarning('', []), TypeError);
assert.throws(() => process.emitWarning('', '', []), TypeError);

0 comments on commit 5e1f32f

Please sign in to comment.