From 237b40c4b4259df70646d8aaf7c4477bd66acdc0 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Fri, 31 Mar 2023 16:56:09 +0200 Subject: [PATCH 1/6] feat: add unlimited option --- README.md | 13 +++++++++++-- index.js | 9 ++++++--- package.json | 1 + test/emit-unlimited.test.js | 34 ++++++++++++++++++++++++++++++++++ test/index.test.js | 8 ++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/emit-unlimited.test.js diff --git a/README.md b/README.md index 3c7aade..f8ea3f7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/) 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. +It also exposes a utility for emitting those warnings, guaranteeing that they are issued only once (or more by setting it). This module is used by the [Fastify](https://fastify.io) framework and it was called `fastify-warning` prior to version 1.0.0. @@ -26,12 +26,13 @@ const warning = require('process-warning')() #### Methods ``` -warning.create(name, code, message) +warning.create(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 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. +- `unlimitedEmits` (`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. @@ -64,6 +65,14 @@ warning.emit('FST_ERROR_CODE', 'world') console.log(warning.emitted.get('FST_ERROR_CODE')) // true ``` +How to use an unlimited warning: +```js +const warning = require('process-warning')() +warning.create('FastifyWarning', 'FST_ERROR_CODE', 'Hello %s', true) +warning.emit('FST_ERROR_CODE', 'world') // will be emitted +warning.emit('FST_ERROR_CODE', 'world') // will be emitted again +``` + ## License Licensed under [MIT](./LICENSE). diff --git a/index.js b/index.js index bcfa955..132e824 100644 --- a/index.js +++ b/index.js @@ -5,11 +5,13 @@ const { format } = require('util') function processWarning () { const codes = {} const emitted = new Map() + let unlimited = false - function create (name, code, message) { + function create (name, code, message, unlimitedEmits = 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 unlimitedEmits !== 'boolean') throw new Error('Warning unlimitedEmits must be a boolean') code = code.toUpperCase() @@ -37,14 +39,15 @@ function processWarning () { } } - emitted.set(code, false) + unlimited = unlimitedEmits + emitted.set(code, unlimited) codes[code] = buildWarnOpts return codes[code] } function emit (code, a, b, c) { - if (emitted.get(code) === true) return + if (emitted.get(code) === true && !unlimited) return if (codes[code] === undefined) throw new Error(`The code '${code}' does not exist`) emitted.set(code, true) diff --git a/package.json b/package.json index b9c4399..6e2630e 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "types": "types/index.d.ts", "scripts": { "lint": "standard", + "lint:fix": "standard --fix", "test": "npm run test:unit && npm run test:jest && npm run test:typescript", "test:jest": "jest jest.test.js", "test:unit": "tap", diff --git a/test/emit-unlimited.test.js b/test/emit-unlimited.test.js new file mode 100644 index 0000000..2bbb90f --- /dev/null +++ b/test/emit-unlimited.test.js @@ -0,0 +1,34 @@ +'use strict' + +const test = require('tap').test +const build = 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.code, 'CODE') + t.equal(warning.message, 'Hello world') + t.ok(emitted.get('CODE')) + t.equal(runs++, expectedRun.shift()) + } + + create('FastifyDeprecation', 'CODE', 'Hello world', true) + + for (let i = 0; i < times; i++) { + expectedRun.push(i) + emit('CODE') + } + setImmediate(() => { + process.removeListener('warning', onWarning) + t.end() + }) +}) diff --git a/test/index.test.js b/test/index.test.js index b00b478..16fc467 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -89,3 +89,11 @@ test('Cannot reuse the same code more than once', t => { t.throws(() => create('FastifyWarning', 'CODE', 'Not available'), new Error("The code 'CODE' already exist")) }) + +test('Cannot set unlimitedEmit other than boolean', t => { + t.plan(1) + + const { create } = build() + + t.throws(() => create('FastifyWarning', 'CODE', 'Msg', 42), new Error('Warning unlimitedEmits must be a boolean')) +}) From c069869aa072c3a67bb48557416c985e7889304e Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Fri, 31 Mar 2023 19:01:48 +0200 Subject: [PATCH 2/6] Update index.js Co-authored-by: James Sumners --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 132e824..3326af4 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,7 @@ function processWarning () { } function emit (code, a, b, c) { - if (emitted.get(code) === true && !unlimited) return + if (emitted.get(code) === true && unlimited === false) return if (codes[code] === undefined) throw new Error(`The code '${code}' does not exist`) emitted.set(code, true) From d4a338a78b26f84fa3825c4c80aed1c7c6dde2b1 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Fri, 31 Mar 2023 19:02:00 +0200 Subject: [PATCH 3/6] Update README.md Co-authored-by: James Sumners --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8ea3f7..f13dab9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/) 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 (or more by setting it). +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. From 6047836fa65293882a8325a8ff164819d9f74a20 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sat, 1 Apr 2023 08:51:20 +0200 Subject: [PATCH 4/6] fix to options --- README.md | 5 +++-- index.js | 10 +++++----- test/emit-unlimited.test.js | 2 +- test/index.test.js | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f13dab9..1c6bb94 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,8 @@ warning.create(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 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. -- `unlimitedEmits` (`boolean`, optional) - Should the warning be emitted more than once? Defaults to `false`. +- `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. @@ -68,7 +69,7 @@ console.log(warning.emitted.get('FST_ERROR_CODE')) // true How to use an unlimited warning: ```js const warning = require('process-warning')() -warning.create('FastifyWarning', 'FST_ERROR_CODE', 'Hello %s', true) +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 ``` diff --git a/index.js b/index.js index 3326af4..d281947 100644 --- a/index.js +++ b/index.js @@ -5,13 +5,13 @@ const { format } = require('util') function processWarning () { const codes = {} const emitted = new Map() - let unlimited = false + const opts = Object.create(null) - function create (name, code, message, unlimitedEmits = false) { + 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 unlimitedEmits !== 'boolean') throw new Error('Warning unlimitedEmits must be a boolean') + if (typeof unlimited !== 'boolean') throw new Error('Warning opts.unlimited must be a boolean') code = code.toUpperCase() @@ -39,7 +39,7 @@ function processWarning () { } } - unlimited = unlimitedEmits + Object.assign(opts, { unlimited }) emitted.set(code, unlimited) codes[code] = buildWarnOpts @@ -47,7 +47,7 @@ function processWarning () { } function emit (code, a, b, c) { - if (emitted.get(code) === true && unlimited === false) return + 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) diff --git a/test/emit-unlimited.test.js b/test/emit-unlimited.test.js index 2bbb90f..b5ff28b 100644 --- a/test/emit-unlimited.test.js +++ b/test/emit-unlimited.test.js @@ -21,7 +21,7 @@ test('emit should emit a given code unlimited times', t => { t.equal(runs++, expectedRun.shift()) } - create('FastifyDeprecation', 'CODE', 'Hello world', true) + create('FastifyDeprecation', 'CODE', 'Hello world', { unlimited: true }) for (let i = 0; i < times; i++) { expectedRun.push(i) diff --git a/test/index.test.js b/test/index.test.js index 16fc467..45af1f6 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -90,10 +90,10 @@ test('Cannot reuse the same code more than once', t => { t.throws(() => create('FastifyWarning', 'CODE', 'Not available'), new Error("The code 'CODE' already exist")) }) -test('Cannot set unlimitedEmit other than boolean', t => { +test('Cannot set unlimited other than boolean', t => { t.plan(1) const { create } = build() - t.throws(() => create('FastifyWarning', 'CODE', 'Msg', 42), new Error('Warning unlimitedEmits must be a boolean')) + t.throws(() => create('FastifyWarning', 'CODE', 'Msg', { unlimited: 42 }), new Error('Warning opts.unlimited must be a boolean')) }) From 41b69bac334a010ca4714d98b68d1162d378fef8 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sat, 1 Apr 2023 08:51:33 +0200 Subject: [PATCH 5/6] feat: add types --- types/index.d.ts | 6 +++++- types/index.test-d.ts | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 4d65031..5ab6754 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,13 +2,17 @@ type ProcessWarning = () => processWarning.Warning declare namespace processWarning { export interface Warning { - create(name: string, code: string, message: string): BuildWarnOptsFn, + create(name: string, code: string, message: string, opts?: ProcessWarningOptions): BuildWarnOptsFn, emit(cod: string, a?: any, b?: any, c?: any): void, emitted: Map } export type BuildWarnOptsFn = (a?: any, b?: any, c?: any) => WarnOpts + export type ProcessWarningOptions = { + unlimited?: boolean, + } + export interface WarnOpts { code: string; name: string; diff --git a/types/index.test-d.ts b/types/index.test-d.ts index a225b5c..b229039 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -12,3 +12,6 @@ expectType(opts.name) expectType(warning.emit('CODE')) expectType>(warning.emitted) + +const buildWarnUnlimited = warning.create('FastifyWarning', 'CODE', 'message', { unlimited: true }) +expectType(buildWarnUnlimited) \ No newline at end of file From e287ff1c92513f0796582e9c8816665c774cee03 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sat, 1 Apr 2023 10:44:24 +0200 Subject: [PATCH 6/6] Update README.md Co-authored-by: KaKa --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c6bb94..a8accb9 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ const warning = require('process-warning')() #### Methods ``` -warning.create(name, code, message, unlimited) +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`