Skip to content

Commit

Permalink
Merge pull request #87 from fastify/support-deprecation-warnings
Browse files Browse the repository at this point in the history
Add createDeprecation method
  • Loading branch information
jsumners committed Oct 27, 2023
2 parents 84b271d + 3be4cb3 commit 5c8ed1f
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 12 deletions.
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,35 @@ const warning = require('process-warning')()

#### Methods

```
warning.create(name, code, message[, options])
```
##### `warning.create(name, code, message[, options])`

- `name` (`string`, required) - The error name, you can access it later with `error.name`. For consistency, we recommend prefixing module error names with `{YourModule}Warning`
- `code` (`string`, required) - The warning code, you can access it later with `error.code`. For consistency, we recommend prefixing plugin error codes with `{ThreeLetterModuleName}_`, e.g. `FST_`. NOTE: codes should be all uppercase.
- `message` (`string`, required) - The warning message. You can also use interpolated strings for formatting the message.
- `options` (`object`, optional) - Optional options with the following properties:
- `unlimited` (`boolean`, optional) - Should the warning be emitted more than once? Defaults to `false`.
- `name` (`string`, required) - The error name, you can access it later with
`error.name`. For consistency, we recommend prefixing module error names
with `{YourModule}Warning`
- `code` (`string`, required) - The warning code, you can access it later with
`error.code`. For consistency, we recommend prefixing plugin error codes with
`{ThreeLetterModuleName}_`, e.g. `FST_`. NOTE: codes should be all uppercase.
- `message` (`string`, required) - The warning message. You can also use
interpolated strings for formatting the message.
- `options` (`object`, optional) - Optional options with the following
properties:
+ `unlimited` (`boolean`, optional) - Should the warning be emitted more than
once? Defaults to `false`.

The utility also contains an `emit` function that you can use for emitting the warnings you have previously created by passing their respective code. A warning is guaranteed to be emitted only once.

```
warning.emit(code [, a [, b [, c]]])
```
##### `warning.createDeprecation(code, message[, options])`

This is a wrapper for `warning.create`. It is equivalent to invoking
`warning.create` with the `name` parameter set to "DeprecationWarning".

Deprecation warnings have extended support for the Node.js CLI options:
`--throw-deprecation`, `--no-deprecation`, and `--trace-deprecation`.

##### `warning.emit(code [, a [, b [, c]]])`

The utility also contains an `emit` function that you can use for emitting the
warnings you have previously created by passing their respective code.
A warning is guaranteed to be emitted at least once.

- `code` (`string`, required) - The warning code you intend to emit.
- `[, a [, b [, c]]]` (`any`, optional) - Parameters for string interpolation.
Expand Down
91 changes: 91 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,63 @@

const { format } = require('node:util')

/**
* An object that provides methods for creating process warning, emitting them,
* and inspecting/managing the emission state of warning.
*
* @typedef {object} ProcessWarningManager
*/

/**
* @typedef {object} CreateOptions
* @property {boolean} [unlimited=false] Indicates if the warning should be
* emitted every time (`true`) or only the first time (`false`).
*/

/**
* An error instance representing a process warning. This is what will be
* emitted to listeners when the warning is emitted.
*
* @typedef {Error} ProcessWarning
* @property {string} code
* @property {string} name
* @property {string} message
*/

/**
* A function used to create new {@link ProcessWarning} instances.
*
* @callback ProcessWarningBuilder
* @param {*} [param1] First possible string interpolation value.
* @param {*} [param2] Second possible string interpolation value.
* @param {*} [param3] Third possible string interpolation value.
* @returns ProcessWarning
*/

/**
* Factory that builds a new {@link ProcessWarningManager} and returns it.
*
* @returns ProcessWarningManager
*/
function processWarning () {
const codes = {}
const emitted = new Map()
const opts = Object.create(null)

/**
* Builds a new {@link ProcessWarning} and adds it to the
* {@link ProcessWarningManager} such that it can be emitted through the
* {@link ProcessWarningManager#emit} method.
*
* @memberof! ProcessWarningManager
* @instance
*
* @param {string} name Warning name, e.g. `'MyCustomWarning'`.
* @param {string} code A unique code for the warning, e.g. `'WARN_001'`.
* @param {string} message The body of the warning.
* @param {CreateOptions} [options]
* @returns {ProcessWarningBuilder}
*/
function create (name, code, message, { unlimited = false } = {}) {
if (!name) throw new Error('Warning name must not be empty')
if (!code) throw new Error('Warning code must not be empty')
Expand Down Expand Up @@ -46,6 +98,44 @@ function processWarning () {
return codes[code]
}

/**
* A wrapper for {@link ProcessWarningManager#create} that builds a new
* deprecation warning. This method is equivalent to passing
* `name = 'DeprecationWarning'` to the create method.
*
* Deprecation warnings have extended support for the Node.js CLI options:
* `--throw-deprecation`, `--no-deprecation`, and `--trace-deprecation`.
*
* @memberof! ProcessWarningManager
* @instance
*
* @param {string} code
* @param {string} message
* @param {CreateOptions} opts
* @returns {ProcessWarningBuilder}
*/
function createDeprecation (code, message, opts = {}) {
return create('DeprecationWarning', code, message, opts)
}

/**
* Emits a registered warning associated with the given `code`. If the
* warning message has interpolation strings present, up to the first three
* of them can be supplied values with the optional interpolation value
* parameters.
*
* If a warning is set to `unlimited: false`, and has already been emitted
* once, invoking this method is a no-operation.
*
* @memberof! ProcessWarningManager
* @instance
*
* @param {string} code The code for the error to emit, e.g. `'WARN_001'`.
* This is the same code that was provided to {@link ProcessWarningManager#create}.
* @param {*} [a] Possible message interpolation value.
* @param {*} [b] Possible message interpolation value.
* @param {*} [c] Possible message interpolation value.
*/
function emit (code, a, b, c) {
if (emitted.get(code) === true && opts.unlimited === false) return
if (codes[code] === undefined) throw new Error(`The code '${code}' does not exist`)
Expand All @@ -57,6 +147,7 @@ function processWarning () {

return {
create,
createDeprecation,
emit,
emitted
}
Expand Down
11 changes: 11 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ test('Create error with 3 parameters', t => {
t.equal(opts.code, 'CODE')
})

test('Creates a deprecation warning', t => {
t.plan(3)

const manager = build()
const builder = manager.createDeprecation('CODE', 'hello %s')
const warning = builder('world')
t.equal(warning.name, 'DeprecationWarning')
t.equal(warning.message, 'hello world')
t.equal(warning.code, 'CODE')
})

test('Should throw when error code has no fastify name', t => {
t.plan(1)

Expand Down

0 comments on commit 5c8ed1f

Please sign in to comment.