diff --git a/README.md b/README.md index 92bdda7..56b0a58 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A small utility for generating consistent warning objects across your codebase. It also exposes a utility for emitting those warnings, guaranteeing that they are issued only once (unless configured otherwise). -This module is used by the [Fastify](https://fastify.io) framework and it was called `fastify-warning` prior to version 1.0.0. +_This module is used by the [Fastify](https://fastify.io) framework and it was called `fastify-warning` prior to version 1.0.0._ ### Install @@ -17,15 +17,26 @@ npm i process-warning ### Usage -The module exports a builder function that returns a utility for creating warnings and emitting them. +The module exports two builder functions for creating warnings. ```js -const warning = require('process-warning')() +const { + createWarning, + createDeprecation +} = require('process-warning') + +const warning = createWarning({ + name: 'ExampleWarning', + code: 'EXP_WRN_001', + message: 'Hello %s', + unlimited: true +}) +warning('world') ``` #### Methods -##### `warning.create(name, code, message[, options])` +##### `createWarning({ name, code, message[, unlimited] })` - `name` (`string`, required) - The error name, you can access it later with `error.name`. For consistency, we recommend prefixing module error names @@ -41,51 +52,53 @@ properties: once? Defaults to `false`. -##### `warning.createDeprecation(code, message[, options])` +##### `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". +This is a wrapper for `createWarning`. It is equivalent to invoking +`createWarning` 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]]])` +##### `warning([, 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. +The returned `warning` function can used for emitting warnings. 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. ```js -const warning = require('process-warning')() -warning.create('FastifyWarning', 'FST_ERROR_CODE', 'message') -warning.emit('FST_ERROR_CODE') +const { createWarning } = require('process-warning') +const FST_ERROR_CODE = createWarning({ name: 'MyAppWarning', code: 'FST_ERROR_CODE', message: 'message' }) +FST_ERROR_CODE() ``` How to use an interpolated string: ```js -const warning = require('process-warning')() -warning.create('FastifyWarning', 'FST_ERROR_CODE', 'Hello %s') -warning.emit('FST_ERROR_CODE', 'world') +const { createWarning } = require('process-warning') +const FST_ERROR_CODE = createWarning({ name: 'MyAppWarning', code: 'FST_ERROR_CODE', message: 'Hello %s'}) +FST_ERROR_CODE('world') ``` -The module also exports an `warning.emitted` [Map](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Map), which contains all the warnings already emitted. Useful for testing. +The `warning` object has methods and properties for managing the warning's state. Useful for testing. ```js -const warning = require('process-warning')() -warning.create('FastifyWarning', 'FST_ERROR_CODE', 'Hello %s') -console.log(warning.emitted.get('FST_ERROR_CODE')) // false -warning.emit('FST_ERROR_CODE', 'world') -console.log(warning.emitted.get('FST_ERROR_CODE')) // true +const { createWarning } = require('process-warning') +const FST_ERROR_CODE = createWarning({ name: 'MyAppWarning', code: 'FST_ERROR_CODE', message: 'Hello %s'}) +console.log(FST_ERROR_CODE.emitted) // false +FST_ERROR_CODE('world') +console.log(FST_ERROR_CODE.emitted) // true + +const FST_ERROR_CODE_2 = createWarning('MyAppWarning', 'FST_ERROR_CODE_2', 'Hello %s') +FST_ERROR_CODE_2.emitted = true +FST_ERROR_CODE_2('world') // will not be emitted because it is not unlimited ``` How to use an unlimited warning: ```js -const warning = require('process-warning')() -warning.create('FastifyWarning', 'FST_ERROR_CODE', 'Hello %s', { unlimited: true }) -warning.emit('FST_ERROR_CODE', 'world') // will be emitted -warning.emit('FST_ERROR_CODE', 'world') // will be emitted again +const { createWarning } = require('process-warning') +const FST_ERROR_CODE = createWarning({ name: 'MyAppWarning', code: 'FST_ERROR_CODE', message: 'Hello %s', unlimited: true }) +FST_ERROR_CODE('world') // will be emitted +FST_ERROR_CODE('world') // will be emitted again ``` #### Suppressing warnings diff --git a/benchmarks/warn.js b/benchmarks/warn.js index 8a191b4..1f49bf6 100644 --- a/benchmarks/warn.js +++ b/benchmarks/warn.js @@ -1,15 +1,23 @@ 'use strict' const { Suite } = require('benchmark') -const warning = require('..')() +const { createWarning } = require('..') + +const err1 = createWarning({ + name: 'TestWarning', + code: 'TST_ERROR_CODE_1', + message: 'message' +}) +const err2 = createWarning({ + name: 'TestWarning', + code: 'TST_ERROR_CODE_2', + message: 'message' +}) -warning.create('FastifyWarning', 'FST_ERROR_CODE_1', 'message') -warning.create('FastifyWarning', 'FST_ERROR_CODE_2', 'message') -warning.create('FastifyWarning', 'FST_ERROR_CODE_3', 'message') new Suite() .add('warn', function () { - warning.emit('FST_ERROR_CODE_1') - warning.emit('FST_ERROR_CODE_3') + err1() + err2() }) .on('cycle', function (event) { console.log(String(event.target)) diff --git a/examples/example.js b/examples/example.js index d6733fd..db9d862 100644 --- a/examples/example.js +++ b/examples/example.js @@ -1,7 +1,11 @@ 'use strict' -const warning = require('..')() +const { createWarning } = require('..') -warning.create('DeprecationWarning', 'CUSTDEP001', 'This is a deprecation warning') +const CUSTDEP001 = createWarning({ + name: 'DeprecationWarning', + code: 'CUSTDEP001', + message: 'This is a deprecation warning' +}) -warning.emit('CUSTDEP001') +CUSTDEP001() diff --git a/index.js b/index.js index 1e7f87f..e0d4ab8 100644 --- a/index.js +++ b/index.js @@ -3,156 +3,122 @@ 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 + * @namespace processWarning */ /** - * @typedef {object} CreateOptions - * @property {boolean} [unlimited=false] Indicates if the warning should be - * emitted every time (`true`) or only the first time (`false`). + * Represents a warning item with details. + * @typedef {Function} WarningItem + * @param {*} [a] Possible message interpolation value. + * @param {*} [b] Possible message interpolation value. + * @param {*} [c] Possible message interpolation value. + * @property {string} name - The name of the warning. + * @property {string} code - The code associated with the warning. + * @property {string} message - The warning message. + * @property {boolean} emitted - Indicates if the warning has been emitted. + * @property {function} format - Formats the warning message. */ /** - * 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 + * Options for creating a process warning. + * @typedef {Object} ProcessWarningOptions + * @property {string} name - The name of the warning. + * @property {string} code - The code associated with the warning. + * @property {string} message - The warning message. + * @property {boolean} [unlimited=false] - If true, allows unlimited emissions of the warning. */ /** - * 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 + * Represents the process warning functionality. + * @typedef {Object} ProcessWarning + * @property {function} createWarning - Creates a warning item. + * @property {function} createDeprecation - Creates a deprecation warning item. */ /** - * Factory that builds a new {@link ProcessWarningManager} and returns it. - * - * @returns ProcessWarningManager + * Creates a deprecation warning item. + * @function + * @memberof processWarning + * @param {ProcessWarningOptions} params - Options for creating the warning. + * @returns {WarningItem} The created deprecation warning item. */ -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') - if (!message) throw new Error('Warning message must not be empty') - if (typeof unlimited !== 'boolean') throw new Error('Warning opts.unlimited must be a boolean') - - code = code.toUpperCase() - - if (codes[code] !== undefined) { - throw new Error(`The code '${code}' already exist`) - } +function createDeprecation (params) { + return createWarning({ ...params, name: 'DeprecationWarning' }) +} - function buildWarnOpts (a, b, c) { - // more performant than spread (...) operator - let formatted - if (a && b && c) { - formatted = format(message, a, b, c) - } else if (a && b) { - formatted = format(message, a, b) - } else if (a) { - formatted = format(message, a) - } else { - formatted = message +/** + * Creates a warning item. + * @function + * @memberof processWarning + * @param {ProcessWarningOptions} params - Options for creating the warning. + * @returns {WarningItem} The created warning item. + * @throws {Error} Throws an error if name, code, or message is empty, or if opts.unlimited is not a boolean. + */ +function createWarning ({ 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') + if (!message) throw new Error('Warning message must not be empty') + if (typeof unlimited !== 'boolean') throw new Error('Warning opts.unlimited must be a boolean') + + code = code.toUpperCase() + + let warningContainer = { + [name]: function (a, b, c) { + if (warning.emitted === true && warning.unlimited !== true) { + return } - - return { - code, - name, - message: formatted + warning.emitted = true + process.emitWarning(warning.format(a, b, c), warning.name, warning.code) + } + } + if (unlimited) { + warningContainer = { + [name]: function (a, b, c) { + warning.emitted = true + process.emitWarning(warning.format(a, b, c), warning.name, warning.code) } } - - Object.assign(opts, { unlimited }) - emitted.set(code, unlimited) - codes[code] = buildWarnOpts - - 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) - } + const warning = warningContainer[name] + + warning.emitted = false + warning.message = message + warning.unlimited = unlimited + warning.code = code /** - * 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}. + * Formats the warning message. * @param {*} [a] Possible message interpolation value. * @param {*} [b] Possible message interpolation value. * @param {*} [c] Possible message interpolation value. + * @returns {string} The formatted warning message. */ - 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`) - emitted.set(code, true) - - const warning = codes[code](a, b, c) - process.emitWarning(warning.message, warning.name, warning.code) + warning.format = function (a, b, c) { + let formatted + if (a && b && c) { + formatted = format(message, a, b, c) + } else if (a && b) { + formatted = format(message, a, b) + } else if (a) { + formatted = format(message, a) + } else { + formatted = message + } + return formatted } - return { - create, - createDeprecation, - emit, - emitted - } + return warning } -module.exports = processWarning -module.exports.default = processWarning -module.exports.processWarning = processWarning +/** + * Module exports containing the process warning functionality. + * @namespace + * @property {function} createWarning - Creates a warning item. + * @property {function} createDeprecation - Creates a deprecation warning item. + * @property {ProcessWarning} processWarning - Represents the process warning functionality. + */ +const out = { createWarning, createDeprecation } +module.exports = out +module.exports.default = out +module.exports.processWarning = out diff --git a/test/emit-interpolated-string.test.js b/test/emit-interpolated-string.test.js index c282a3c..7a5b9d6 100644 --- a/test/emit-interpolated-string.test.js +++ b/test/emit-interpolated-string.test.js @@ -1,23 +1,26 @@ 'use strict' const test = require('tap').test -const build = require('..') +const { createWarning } = require('..') test('emit with interpolated string', t => { t.plan(4) - const { create, emit, emitted } = build() process.on('warning', onWarning) function onWarning (warning) { - t.equal(warning.name, 'FastifyDeprecation') + t.equal(warning.name, 'TestDeprecation') t.equal(warning.code, 'CODE') t.equal(warning.message, 'Hello world') - t.ok(emitted.get('CODE')) + t.ok(codeWarning.emitted) } - create('FastifyDeprecation', 'CODE', 'Hello %s') - emit('CODE', 'world') - emit('CODE', 'world') + const codeWarning = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello %s' + }) + codeWarning('world') + codeWarning('world') setImmediate(() => { process.removeListener('warning', onWarning) diff --git a/test/emit-once-only.test.js b/test/emit-once-only.test.js index e1d8a30..a14d06c 100644 --- a/test/emit-once-only.test.js +++ b/test/emit-once-only.test.js @@ -1,24 +1,26 @@ 'use strict' const test = require('tap').test -const build = require('..') +const { createWarning } = require('..') test('emit should emit a given code only once', t => { t.plan(4) - const { create, emit, emitted } = build() - process.on('warning', onWarning) function onWarning (warning) { - t.equal(warning.name, 'FastifyDeprecation') + t.equal(warning.name, 'TestDeprecation') t.equal(warning.code, 'CODE') t.equal(warning.message, 'Hello world') - t.ok(emitted.get('CODE')) + t.ok(warn.emitted) } - create('FastifyDeprecation', 'CODE', 'Hello world') - emit('CODE') - emit('CODE') + const warn = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello world' + }) + warn() + warn() setImmediate(() => { process.removeListener('warning', onWarning) t.end() diff --git a/test/emit-reset.test.js b/test/emit-reset.test.js new file mode 100644 index 0000000..cdfc635 --- /dev/null +++ b/test/emit-reset.test.js @@ -0,0 +1,36 @@ +'use strict' + +const test = require('tap').test +const { createWarning } = require('../') + +test('a limited warning can be re-set', t => { + t.plan(4) + + let count = 0 + process.on('warning', onWarning) + function onWarning () { + count++ + } + + const warn = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello world' + }) + + warn() + t.ok(warn.emitted) + + warn() + t.ok(warn.emitted) + + warn.emitted = false + warn() + t.ok(warn.emitted) + + setImmediate(() => { + t.equal(count, 2) + process.removeListener('warning', onWarning) + t.end() + }) +}) diff --git a/test/emit-set.test.js b/test/emit-set.test.js new file mode 100644 index 0000000..695132c --- /dev/null +++ b/test/emit-set.test.js @@ -0,0 +1,30 @@ +'use strict' + +const test = require('tap').test +const { createWarning } = require('../') + +test('emit should set the emitted state', t => { + t.plan(3) + + process.on('warning', onWarning) + function onWarning () { + t.fail('should not be called') + } + + const warn = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello world' + }) + t.notOk(warn.emitted) + warn.emitted = true + t.ok(warn.emitted) + + warn() + t.ok(warn.emitted) + + setImmediate(() => { + process.removeListener('warning', onWarning) + t.end() + }) +}) diff --git a/test/emit-unlimited.test.js b/test/emit-unlimited.test.js index b5ff28b..bfce3e3 100644 --- a/test/emit-unlimited.test.js +++ b/test/emit-unlimited.test.js @@ -1,31 +1,34 @@ 'use strict' const test = require('tap').test -const build = require('..') +const { createWarning } = require('..') test('emit should emit a given code unlimited times', t => { t.plan(50) - const { create, emit, emitted } = build() - let runs = 0 const expectedRun = [] const times = 10 process.on('warning', onWarning) function onWarning (warning) { - t.equal(warning.name, 'FastifyDeprecation') + t.equal(warning.name, 'TestDeprecation') t.equal(warning.code, 'CODE') t.equal(warning.message, 'Hello world') - t.ok(emitted.get('CODE')) + t.ok(warn.emitted) t.equal(runs++, expectedRun.shift()) } - create('FastifyDeprecation', 'CODE', 'Hello world', { unlimited: true }) + const warn = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello world', + unlimited: true + }) for (let i = 0; i < times; i++) { expectedRun.push(i) - emit('CODE') + warn() } setImmediate(() => { process.removeListener('warning', onWarning) diff --git a/test/index.test.js b/test/index.test.js index 4765b12..59a3676 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,110 +1,99 @@ 'use strict' const test = require('tap').test -const build = require('..') +const { createWarning, createDeprecation } = require('..') process.removeAllListeners('warning') test('Create warning with zero parameter', t => { t.plan(3) - const { create } = build() - const buildWarnOpts = create('FastifyWarning', 'CODE', 'Not available') - const opts = buildWarnOpts() - t.equal(opts.name, 'FastifyWarning') - t.equal(opts.message, 'Not available') - t.equal(opts.code, 'CODE') + const warnItem = createWarning({ + name: 'TestWarning', + code: 'CODE', + message: 'Not available' + }) + t.equal(warnItem.name, 'TestWarning') + t.equal(warnItem.message, 'Not available') + t.equal(warnItem.code, 'CODE') }) test('Create error with 1 parameter', t => { t.plan(3) - const { create } = build() - const buildWarningOpts = create('FastifyWarning', 'CODE', 'hey %s') - const opts = buildWarningOpts('alice') - t.equal(opts.name, 'FastifyWarning') - t.equal(opts.message, 'hey alice') - t.equal(opts.code, 'CODE') + const warnItem = createWarning({ + name: 'TestWarning', + code: 'CODE', + message: 'hey %s' + }) + t.equal(warnItem.name, 'TestWarning') + t.equal(warnItem.format('alice'), 'hey alice') + t.equal(warnItem.code, 'CODE') }) test('Create error with 2 parameters', t => { t.plan(3) - const { create } = build() - const buildWarnOpts = create('FastifyWarning', 'CODE', 'hey %s, I like your %s') - const opts = buildWarnOpts('alice', 'attitude') - t.equal(opts.name, 'FastifyWarning') - t.equal(opts.message, 'hey alice, I like your attitude') - t.equal(opts.code, 'CODE') + const warnItem = createWarning({ + name: 'TestWarning', + code: 'CODE', + message: 'hey %s, I like your %s' + }) + t.equal(warnItem.name, 'TestWarning') + t.equal(warnItem.format('alice', 'attitude'), 'hey alice, I like your attitude') + t.equal(warnItem.code, 'CODE') }) test('Create error with 3 parameters', t => { t.plan(3) - const { create } = build() - const buildWarnOpts = create('FastifyWarning', 'CODE', 'hey %s, I like your %s %s') - const opts = buildWarnOpts('alice', 'attitude', 'see you') - t.equal(opts.name, 'FastifyWarning') - t.equal(opts.message, 'hey alice, I like your attitude see you') - t.equal(opts.code, 'CODE') + const warnItem = createWarning({ + name: 'TestWarning', + code: 'CODE', + message: 'hey %s, I like your %s %s' + }) + t.equal(warnItem.name, 'TestWarning') + t.equal(warnItem.format('alice', 'attitude', 'see you'), 'hey alice, I like your attitude see you') + t.equal(warnItem.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') + const deprecationItem = createDeprecation({ + name: 'DeprecationWarning', + code: 'CODE', + message: 'hello %s' + }) + t.equal(deprecationItem.name, 'DeprecationWarning') + t.equal(deprecationItem.format('world'), 'hello world') + t.equal(deprecationItem.code, 'CODE') }) -test('Should throw when error code has no fastify name', t => { +test('Should throw when error code has no name', t => { t.plan(1) - - const { create } = build() - - t.throws(() => create(), new Error('Warning name must not be empty')) + t.throws(() => createWarning(), new Error('Warning name must not be empty')) }) test('Should throw when error has no code', t => { t.plan(1) - - const { create } = build() - - t.throws(() => create('name'), new Error('Warning code must not be empty')) + t.throws(() => createWarning({ name: 'name' }), new Error('Warning code must not be empty')) }) test('Should throw when error has no message', t => { t.plan(1) - - const { create } = build() - - t.throws(() => create('name', 'code'), new Error('Warning message must not be empty')) -}) - -test('Should throw if emit is called with unknown code ', t => { - t.plan(1) - - const { emit } = build() - - t.throws(() => emit('CODE'), new Error('The code \'CODE\' does not exist')) -}) - -test('Cannot reuse the same code more than once', t => { - t.plan(1) - - const { create } = build() - create('FastifyWarning', 'CODE', 'Not available') - - t.throws(() => create('FastifyWarning', 'CODE', 'Not available'), new Error("The code 'CODE' already exist")) + t.throws(() => createWarning({ + name: 'name', + code: 'code' + }), new Error('Warning message must not be empty')) }) test('Cannot set unlimited other than boolean', t => { t.plan(1) - - const { create } = build() - - t.throws(() => create('FastifyWarning', 'CODE', 'Msg', { unlimited: 42 }), new Error('Warning opts.unlimited must be a boolean')) + t.throws(() => createWarning({ + name: 'name', + code: 'code', + message: 'message', + unlimited: 'unlimited' + }), new Error('Warning opts.unlimited must be a boolean')) }) diff --git a/test/issue-88.test.js b/test/issue-88.test.js new file mode 100644 index 0000000..cc2d66f --- /dev/null +++ b/test/issue-88.test.js @@ -0,0 +1,33 @@ +'use strict' + +const { test } = require('tap') +const { createWarning } = require('..') + +test('Must not overwrite config', t => { + t.plan(1) + + function onWarning (warning) { + t.equal(warning.code, 'CODE_1') + } + + const a = createWarning({ + name: 'TestWarning', + code: 'CODE_1', + message: 'Msg' + }) + createWarning({ + name: 'TestWarning', + code: 'CODE_2', + message: 'Msg', + unlimited: true + }) + + process.on('warning', onWarning) + a('CODE_1') + a('CODE_1') + + setImmediate(() => { + process.removeListener('warning', onWarning) + t.end() + }) +}) diff --git a/test/jest.test.js b/test/jest.test.js index b02660d..894ae76 100644 --- a/test/jest.test.js +++ b/test/jest.test.js @@ -1,20 +1,22 @@ /* global test, expect */ 'use strict' -const build = require('..') +const { createWarning } = require('..') test('works with jest', done => { - const { create, emit, emitted } = build() - - create('FastifyDeprecation', 'CODE', 'Hello %s') - emit('CODE', 'world') + const code = createWarning({ + name: 'TestDeprecation', + code: 'CODE', + message: 'Hello world' + }) + code('world') // we cannot actually listen to process warning event // because jest messes with it (that's the point of this test) // we can only test it was emitted indirectly // and test no exception is raised setImmediate(() => { - expect(emitted.get('CODE')).toBeTruthy() + expect(code.emitted).toBeTruthy() done() }) }) diff --git a/types/index.d.ts b/types/index.d.ts index 5ab6754..a11bab0 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,27 +1,37 @@ -type ProcessWarning = () => processWarning.Warning - declare namespace processWarning { - export interface Warning { - create(name: string, code: string, message: string, opts?: ProcessWarningOptions): BuildWarnOptsFn, - emit(cod: string, a?: any, b?: any, c?: any): void, - emitted: Map + export interface WarningItem { + (a?: any, b?: any, c?: any): void; + name: string; + code: string; + message: string; + emitted: boolean; + unlimited: boolean; + format(a?: any, b?: any, c?: any): string; } - export type BuildWarnOptsFn = (a?: any, b?: any, c?: any) => WarnOpts + export type WarningOptions = { + name: string; + code: string; + message: string; + unlimited?: boolean; + } + + export type DeprecationOptions = Omit export type ProcessWarningOptions = { - unlimited?: boolean, + unlimited?: boolean; } - export interface WarnOpts { - code: string; - name: string; - message: string; + export type ProcessWarning = { + createWarning(params: WarningOptions): WarningItem; + createDeprecation(params: DeprecationOptions): WarningItem; } - export const processWarning: ProcessWarning - export { processWarning as default } + export function createWarning(params: WarningOptions): WarningItem; + export function createDeprecation(params: DeprecationOptions): WarningItem; + + const processWarning: ProcessWarning; + export { processWarning as default }; } -declare function processWarning(...params: Parameters): ReturnType -export = processWarning +export = processWarning; diff --git a/types/index.test-d.ts b/types/index.test-d.ts index b229039..fe338e1 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -1,17 +1,36 @@ import { expectType } from 'tsd' -import Warinig, { BuildWarnOptsFn, WarnOpts } from '..' +import { createWarning, createDeprecation } from '..' -const warning = Warinig() -const buildWarnOpts = warning.create('FastifyWarning', 'CODE', 'message') -expectType(buildWarnOpts) -const opts = buildWarnOpts() -expectType(opts) -expectType(opts.code) -expectType(opts.message) -expectType(opts.name) +const WarnInstance = createWarning({ + name: 'TypeScriptWarning', + code: 'CODE', + message: 'message' +}) -expectType(warning.emit('CODE')) -expectType>(warning.emitted) +expectType(WarnInstance.code) +expectType(WarnInstance.message) +expectType(WarnInstance.name) +expectType(WarnInstance.emitted) +expectType(WarnInstance.unlimited) -const buildWarnUnlimited = warning.create('FastifyWarning', 'CODE', 'message', { unlimited: true }) -expectType(buildWarnUnlimited) \ No newline at end of file +expectType(WarnInstance()) +expectType(WarnInstance('foo')) +expectType(WarnInstance('foo', 'bar')) + +const buildWarnUnlimited = createWarning({ + name: 'TypeScriptWarning', + code: 'CODE', + message: 'message', + unlimited: true +}) +expectType(buildWarnUnlimited.unlimited) + +const DeprecationInstance = createDeprecation({ + code: 'CODE', + message: 'message' +}) +expectType(DeprecationInstance.code) + +DeprecationInstance() +DeprecationInstance('foo') +DeprecationInstance('foo', 'bar')