From 734d06cf5bd2488b4fb5d07996d335076d6dbf47 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Sun, 18 May 2025 17:05:41 +0200 Subject: [PATCH 01/20] feat: implement instanceof --- index.js | 20 +++++++++++++++++++- test/index.test.js | 27 ++++++++++++++++++++++++++- types/index.d.ts | 2 ++ types/index.test-d.ts | 13 +++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 3e2365a..f7b3c49 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,8 @@ const { format } = require('node:util') +const FastifyErrorSymbol = Symbol.for('fastify-error') + function toString () { return `${this.name} [${this.code}]: ${this.message}` } @@ -38,7 +40,13 @@ function createError (code, message, statusCode = 500, Base = Error, captureStac enumerable: false, writable: true, configurable: true - } + }, + [FastifyErrorSymbol]: { + value: true, + enumerable: false, + writable: false, + configurable: false + }, }) FastifyError.prototype[Symbol.toStringTag] = 'Error' @@ -50,6 +58,16 @@ function createError (code, message, statusCode = 500, Base = Error, captureStac createError.captureStackTrace = true +const FastifyErrorConstructor = createError('FST_ERR', 'Fastify Error', 500, Error) +Object.defineProperty(FastifyErrorConstructor, Symbol.hasInstance, { + value: function (instance) { + return instance && instance[FastifyErrorSymbol] + }, + configurable: true, + enumerable: false +}) + module.exports = createError +module.exports.FastifyError = FastifyErrorConstructor module.exports.default = createError module.exports.createError = createError diff --git a/test/index.test.js b/test/index.test.js index beca457..9b927dd 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,7 +1,7 @@ 'use strict' const test = require('node:test') -const createError = require('..') +const { createError, FastifyError } = require('..') test('Create error with zero parameter', (t) => { t.plan(6) @@ -221,3 +221,28 @@ test('Create an error with last argument null', (t) => { t.assert.ok(err instanceof Error) t.assert.ifError(err.cause) }) + +test('check if instanceof works', (t) => { + t.plan(5) + + const NewError = createError('CODE', 'Not available') + const err = NewError() + + const NewFastifySyntaxError = createError('CODE', 'Not available', 500, SyntaxError) + const syntaxErr = NewFastifySyntaxError() + + t.assert.ok(err instanceof Error) + t.assert.ok(err instanceof FastifyError) + t.assert.ok(new Error() instanceof FastifyError === false) + t.assert.ok(syntaxErr instanceof SyntaxError) + t.assert.ok(syntaxErr instanceof FastifyError) +}) + +test('check if FastifyError is instantiable', (t) => { + t.plan(2) + + const err = new FastifyError() + + t.assert.ok(err instanceof FastifyError) + t.assert.ok(err instanceof Error) +}) diff --git a/types/index.d.ts b/types/index.d.ts index 5ef39a3..2e59d9f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -40,6 +40,8 @@ declare namespace createError { readonly prototype: FastifyError & E } + export const FastifyError: FastifyErrorConstructor + export const createError: CreateError export { createError as default } } diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 31316eb..1a4398d 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -77,3 +77,16 @@ expectError(new CustomTypedArgError6('a', 'b', 'c', 'd', 'e')) const CustomErrorWithErrorConstructor = createError('ERROR_CODE', 'message', 500, TypeError) expectType>(CustomErrorWithErrorConstructor) CustomErrorWithErrorConstructor({ cause: new Error('Error') }) +const customErrorWithErrorConstructor = CustomErrorWithErrorConstructor() +if (customErrorWithErrorConstructor instanceof FastifyError) { + expectType<'ERROR_CODE'>(customErrorWithErrorConstructor.code) + expectType(customErrorWithErrorConstructor.message) + expectType<500>(customErrorWithErrorConstructor.statusCode) +} + +const error = new FastifyError('ERROR_CODE', 'message', 500) +if (error instanceof FastifyError) { + expectType(error.code) + expectType(error.message) + expectType(error.statusCode) +} From 49ef1186b00dbdc1bfa7515371bcce2eb1064e09 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Sun, 18 May 2025 17:17:07 +0200 Subject: [PATCH 02/20] improve test --- test/index.test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index 9b927dd..b4a68a1 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -223,19 +223,21 @@ test('Create an error with last argument null', (t) => { }) test('check if instanceof works', (t) => { - t.plan(5) + t.plan(7) const NewError = createError('CODE', 'Not available') const err = NewError() - const NewFastifySyntaxError = createError('CODE', 'Not available', 500, SyntaxError) - const syntaxErr = NewFastifySyntaxError() + const FastifySyntaxError = createError('CODE', 'Not available', 500, SyntaxError) + const syntaxErr = new FastifySyntaxError() t.assert.ok(err instanceof Error) t.assert.ok(err instanceof FastifyError) + t.assert.ok(err instanceof SyntaxError === false) t.assert.ok(new Error() instanceof FastifyError === false) t.assert.ok(syntaxErr instanceof SyntaxError) t.assert.ok(syntaxErr instanceof FastifyError) + t.assert.ok(syntaxErr instanceof FastifySyntaxError) }) test('check if FastifyError is instantiable', (t) => { From 21c11fc15ae1de7e5cdf319ed8029b2b7b828dfd Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Tue, 20 May 2025 17:55:16 +0200 Subject: [PATCH 03/20] add test --- test/index.test.js | 18 ----- test/instanceof.test.js | 168 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 test/instanceof.test.js diff --git a/test/index.test.js b/test/index.test.js index b4a68a1..3ad97f6 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -222,24 +222,6 @@ test('Create an error with last argument null', (t) => { t.assert.ifError(err.cause) }) -test('check if instanceof works', (t) => { - t.plan(7) - - const NewError = createError('CODE', 'Not available') - const err = NewError() - - const FastifySyntaxError = createError('CODE', 'Not available', 500, SyntaxError) - const syntaxErr = new FastifySyntaxError() - - t.assert.ok(err instanceof Error) - t.assert.ok(err instanceof FastifyError) - t.assert.ok(err instanceof SyntaxError === false) - t.assert.ok(new Error() instanceof FastifyError === false) - t.assert.ok(syntaxErr instanceof SyntaxError) - t.assert.ok(syntaxErr instanceof FastifyError) - t.assert.ok(syntaxErr instanceof FastifySyntaxError) -}) - test('check if FastifyError is instantiable', (t) => { t.plan(2) diff --git a/test/instanceof.test.js b/test/instanceof.test.js new file mode 100644 index 0000000..4bdbe2f --- /dev/null +++ b/test/instanceof.test.js @@ -0,0 +1,168 @@ +'use strict' + +const cp = require('node:child_process') +const fs = require('node:fs') +const path = require('node:path') +const os = require('node:os') +const test = require('node:test') +const { createError, FastifyError } = require('..') + +test('check if createError creates an Error which is instanceof Error', (t) => { + t.plan(3) + + const CustomFastifyError = createError('CODE', 'Not available') + const err = CustomFastifyError() + + t.assert.ok(err instanceof Error) + t.assert.ok(err instanceof SyntaxError === false) + t.assert.ok(err instanceof TypeError === false) +}) + +test('check if createError creates an Error which is instanceof FastifyError', (t) => { + t.plan(4) + + const CustomFastifyError = createError('CODE', 'Not available') + const err = CustomFastifyError() + + t.assert.ok(err instanceof Error) + t.assert.ok(err instanceof FastifyError) + t.assert.ok(err instanceof SyntaxError === false) + t.assert.ok(err instanceof TypeError === false) +}) + +test('check if createError creates an Error with the right BaseConstructor', (t) => { + t.plan(2) + + const CustomFastifyError = createError('CODE', 'Not available', 500, TypeError) + const err = CustomFastifyError() + + t.assert.ok(err instanceof Error) + t.assert.ok(err instanceof TypeError) +}) + +test('check if createError creates an Error with the right BaseConstructor, which is a FastifyError', (t) => { + t.plan(6) + + const BaseFastifyError = createError('CODE', 'Not available', 500, TypeError) + const CustomFastifyError = createError('CODE', 'Not available', 500, BaseFastifyError) + const err = CustomFastifyError() + + t.assert.ok(err instanceof Error) + t.assert.ok(err instanceof TypeError) + t.assert.ok(err instanceof FastifyError) + t.assert.ok(err instanceof BaseFastifyError) + t.assert.ok(err instanceof CustomFastifyError) + t.assert.ok(err instanceof SyntaxError === false) +}) + +test('instanceof', async (t) => { + const assertsPlanned = 2 + t.plan(assertsPlanned) + + const testCwd = path.resolve(os.tmpdir()) + + fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'fastify-error'), { recursive: true }) + + fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'index.js')) + fs.copyFileSync(path.resolve(process.cwd(), 'package.json'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'package.json')) + + fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error'), { recursive: true }) + + fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error', 'index.js')) + fs.copyFileSync(path.resolve(process.cwd(), 'package.json'), path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error', 'package.json')) + + fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'main', 'package.json'), ` + { + "name": "main", + "version": "1.0.0", + "description": "main", + "main": "index.js", + "dependencies": { + "fastify-error": "1.0.0" + } + } + `) + fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'main', 'index.js'), ` + 'use strict' + + const { createError } = require('fastify-error') + + const Boom = createError('Boom', 'Boom', 500) + + module.exports.foo = function foo () { + throw new Boom('foo go Boom') + } + `) + + fs.writeFileSync(path.resolve(testCwd, 'package.json'), ` + { + "name": "test", + "version": "1.0.0", + "description": "main", + "main": "index.js", + "dependencies": { + "fastify-error": "1.0.0", + "main": "1.0.0" + } + } + `) + fs.writeFileSync(path.resolve(testCwd, 'index.js'), ` + 'use strict' + const { createError, FastifyError } = require('fastify-error') + const { foo } = require('main') + + const Boom = createError('Boom', 'Boom', 500) + + try { + foo() + } catch (err) { + process.send(err instanceof FastifyError) + process.send(err instanceof Boom) + } + `) + + const finishedPromise = { + promise: undefined, + reject: undefined, + resolve: undefined, + } + + finishedPromise.promise = new Promise((resolve, reject) => { + finishedPromise.resolve = resolve + finishedPromise.reject = reject + }) + + const child = cp.fork(path.resolve(testCwd, 'index.js'), { + cwd: testCwd, + stdio: 'pipe', + env: { + ...process.env, + NODE_OPTIONS: '--no-warnings' + }, + }) + + let messageCount = 0 + child.on('message', message => { + try { + switch (messageCount) { + case 0: + t.assert.strictEqual(message, true, 'instanceof FastifyError') + break + case 1: + t.assert.strictEqual(message, false, 'instanceof Boom') + break + } + if (++messageCount === assertsPlanned) { + finishedPromise.resolve() + } + } catch (err) { + finishedPromise.reject(err) + } + }) + + child.on('error', err => { + finishedPromise.reject(err) + }) + + await finishedPromise.promise +}) From 4e6a67e7668bd11c74f3bfb49ff361761ade3c25 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 09:43:31 +0200 Subject: [PATCH 04/20] why not? --- index.js | 49 ++++++++++++++++++++++++++++++++--------- test/instanceof.test.js | 25 ++++++++++++++++----- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index f7b3c49..4d8da8e 100644 --- a/index.js +++ b/index.js @@ -2,19 +2,27 @@ const { format } = require('node:util') -const FastifyErrorSymbol = Symbol.for('fastify-error') - function toString () { return `${this.name} [${this.code}]: ${this.message}` } +const FastifyGenericErrorSymbol = Symbol.for('fastify-error-generic') + function createError (code, message, statusCode = 500, Base = Error, captureStackTrace = createError.captureStackTrace) { + const shouldCreateFastifyGenericError = code === FastifyGenericErrorSymbol + + if (shouldCreateFastifyGenericError) { + code = 'FST_ERR' + } + if (!code) throw new Error('Fastify error code must not be empty') if (!message) throw new Error('Fastify error message must not be empty') code = code.toUpperCase() !statusCode && (statusCode = undefined) + const FastifySpecificErrorSymbol = Symbol.for(`fastify-error ${code}`) + function FastifyError (...args) { if (!new.target) { return new FastifyError(...args) @@ -41,14 +49,40 @@ function createError (code, message, statusCode = 500, Base = Error, captureStac writable: true, configurable: true }, - [FastifyErrorSymbol]: { + [FastifyGenericErrorSymbol]: { value: true, enumerable: false, writable: false, configurable: false }, + [FastifySpecificErrorSymbol]: { + value: true, + enumerable: false, + writable: false, + configurable: false + } }) + if (shouldCreateFastifyGenericError) { + Object.defineProperty(FastifyError, Symbol.hasInstance, { + value (instance) { + return instance && instance[FastifyGenericErrorSymbol] + }, + configurable: false, + writable: false, + enumerable: false + }) + } else { + Object.defineProperty(FastifyError, Symbol.hasInstance, { + value (instance) { + return instance && instance[FastifySpecificErrorSymbol] + }, + configurable: false, + writable: false, + enumerable: false + }) + } + FastifyError.prototype[Symbol.toStringTag] = 'Error' FastifyError.prototype.toString = toString @@ -58,14 +92,7 @@ function createError (code, message, statusCode = 500, Base = Error, captureStac createError.captureStackTrace = true -const FastifyErrorConstructor = createError('FST_ERR', 'Fastify Error', 500, Error) -Object.defineProperty(FastifyErrorConstructor, Symbol.hasInstance, { - value: function (instance) { - return instance && instance[FastifyErrorSymbol] - }, - configurable: true, - enumerable: false -}) +const FastifyErrorConstructor = createError(FastifyGenericErrorSymbol, 'Fastify Error', 500, Error) module.exports = createError module.exports.FastifyError = FastifyErrorConstructor diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 4bdbe2f..663eea3 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -56,7 +56,7 @@ test('check if createError creates an Error with the right BaseConstructor, whic }) test('instanceof', async (t) => { - const assertsPlanned = 2 + const assertsPlanned = 5 t.plan(assertsPlanned) const testCwd = path.resolve(os.tmpdir()) @@ -88,9 +88,10 @@ test('instanceof', async (t) => { const { createError } = require('fastify-error') const Boom = createError('Boom', 'Boom', 500) + const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) module.exports.foo = function foo () { - throw new Boom('foo go Boom') + throw new ChildBoom('foo go Boom') } `) @@ -112,12 +113,17 @@ test('instanceof', async (t) => { const { foo } = require('main') const Boom = createError('Boom', 'Boom', 500) + const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) + const NotChildBoom = createError('NotChildBoom', 'NotChildBoom', 500, Boom) try { foo() } catch (err) { + process.send(err instanceof Error) process.send(err instanceof FastifyError) + process.send(err instanceof NotChildBoom) process.send(err instanceof Boom) + process.send(err instanceof ChildBoom) } `) @@ -134,7 +140,7 @@ test('instanceof', async (t) => { const child = cp.fork(path.resolve(testCwd, 'index.js'), { cwd: testCwd, - stdio: 'pipe', + stdio: 'inherit', env: { ...process.env, NODE_OPTIONS: '--no-warnings' @@ -146,10 +152,19 @@ test('instanceof', async (t) => { try { switch (messageCount) { case 0: - t.assert.strictEqual(message, true, 'instanceof FastifyError') + t.assert.strictEqual(message, true, 'instanceof Error') break case 1: - t.assert.strictEqual(message, false, 'instanceof Boom') + t.assert.strictEqual(message, true, 'instanceof FastifyError') + break + case 2: + t.assert.strictEqual(message, false, 'instanceof NotChildBoom') + break + case 3: + t.assert.strictEqual(message, true, 'instanceof Boom') + break + case 4: + t.assert.strictEqual(message, true, 'instanceof ChildBoom') break } if (++messageCount === assertsPlanned) { From 4a1cf26640393177a29d4cdf67be360f6c74eaaa Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 16:44:11 +0200 Subject: [PATCH 05/20] rework test --- test/instanceof.test.js | 117 +++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 663eea3..da287bc 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -55,62 +55,42 @@ test('check if createError creates an Error with the right BaseConstructor, whic t.assert.ok(err instanceof SyntaxError === false) }) -test('instanceof', async (t) => { +// for more information see https://github.com/fastify/fastify-error/pull/86#issuecomment-1301466407 +test('ensure that instanceof works accross different installations of the fastify-error module', async (t) => { const assertsPlanned = 5 t.plan(assertsPlanned) - const testCwd = path.resolve(os.tmpdir()) - - fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'fastify-error'), { recursive: true }) - - fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'index.js')) - fs.copyFileSync(path.resolve(process.cwd(), 'package.json'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'package.json')) - - fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error'), { recursive: true }) - - fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error', 'index.js')) - fs.copyFileSync(path.resolve(process.cwd(), 'package.json'), path.resolve(testCwd, 'node_modules', 'main', 'node_modules', 'fastify-error', 'package.json')) - - fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'main', 'package.json'), ` - { - "name": "main", - "version": "1.0.0", - "description": "main", - "main": "index.js", - "dependencies": { - "fastify-error": "1.0.0" - } - } - `) - fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'main', 'index.js'), ` + // We need to create a test environment where fastify-error is installed in two different locations + // and then we will check if the error created in one location is instanceof the error created in the other location + // This is done by creating a test directory with the following structure: + + // / + // ├── index.js + // └── node_modules/ + // ├── fastify-error/ + // │ └── index.js + // └── dep/ + // ├── index.js + // └── node_modules/ + // └── fastify-error/ + // └── index.js + + const testCwd = path.resolve(os.tmpdir(), `fastify-error-instanceof-test-${Math.random().toString(36).substring(2, 15)}`) + fs.mkdirSync(testCwd, { recursive: true }) + + // Create the index.js. It will be executed as a forked process, so we need to + // use process.send to send messages back to the parent process. + fs.writeFileSync(path.resolve(testCwd, 'index.js'), ` 'use strict' - const { createError } = require('fastify-error') - - const Boom = createError('Boom', 'Boom', 500) - const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) - - module.exports.foo = function foo () { - throw new ChildBoom('foo go Boom') - } - `) + const path = require('node:path') + const { createError, FastifyError } = require('fastify-error') + const { foo } = require('dep') - fs.writeFileSync(path.resolve(testCwd, 'package.json'), ` - { - "name": "test", - "version": "1.0.0", - "description": "main", - "main": "index.js", - "dependencies": { - "fastify-error": "1.0.0", - "main": "1.0.0" - } + // Ensure that fastify-error is required from the node_modules directory of the test-project + if (require.resolve('fastify-error') !== path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js')) { + throw new Error('fastify-error should be required from the node_modules directory of the test-project') } - `) - fs.writeFileSync(path.resolve(testCwd, 'index.js'), ` - 'use strict' - const { createError, FastifyError } = require('fastify-error') - const { foo } = require('main') const Boom = createError('Boom', 'Boom', 500) const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) @@ -127,6 +107,38 @@ test('instanceof', async (t) => { } `) + // Create /node_modules/fastify-error directory + // Copy the index.js file to the fastify-error directory + fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'fastify-error'), { recursive: true }) + fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'index.js')) + + // Create /node_modules/dep/node_modules/fastify-error directory + // Copy the index.js to the fastify-error directory + fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'dep', 'node_modules', 'fastify-error'), { recursive: true }) + fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) + + // Create /node_modules/dep/index.js. It will export a function foo which will + // throw an error when called. The error will be an instance of ChildBoom, created + // by the fastify-error module in the node_modules directory of dep. + fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'dep', 'index.js'), ` + 'use strict' + + const path = require('node:path') + const { createError } = require('fastify-error') + + // Ensure that fastify-error is required from the node_modules directory of dep + if (require.resolve('fastify-error') !== path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) { + throw new Error('fastify-error should be required from the node_modules directory of dep') + } + + const Boom = createError('Boom', 'Boom', 500) + const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) + + module.exports.foo = function foo () { + throw new ChildBoom('foo go Boom') + } + `) + const finishedPromise = { promise: undefined, reject: undefined, @@ -180,4 +192,11 @@ test('instanceof', async (t) => { }) await finishedPromise.promise + + // Cleanup + // As we are creating the test-setup on the fly in the /tmp directory, we can remove it + // safely when we are done. It is not relevant for the test if the deletion fails. + try { + fs.rmSync(testCwd, { recursive: true, force: true }) + } catch {} }) From ba70244b1fe869445ae5d68481f645c272dfe5fc Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:08:07 +0200 Subject: [PATCH 06/20] log --- test/instanceof.test.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index da287bc..5c199b8 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -86,7 +86,11 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError, FastifyError } = require('fastify-error') const { foo } = require('dep') - + + console.log({ + actual: require.resolve('fastify-error'), + expected: path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js'), + }) // Ensure that fastify-error is required from the node_modules directory of the test-project if (require.resolve('fastify-error') !== path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js')) { throw new Error('fastify-error should be required from the node_modules directory of the test-project') @@ -126,6 +130,11 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError } = require('fastify-error') + console.log({ + actual: require.resolve('fastify-error'), + expected: path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js'), + }) + // Ensure that fastify-error is required from the node_modules directory of dep if (require.resolve('fastify-error') !== path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) { throw new Error('fastify-error should be required from the node_modules directory of dep') From 1f6b95607b28469295911fcbf2840dd0fdda605b Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:15:41 +0200 Subject: [PATCH 07/20] normalize Path for macos and win --- test/instanceof.test.js | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 5c199b8..4fa4d7e 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -86,13 +86,17 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError, FastifyError } = require('fastify-error') const { foo } = require('dep') - - console.log({ - actual: require.resolve('fastify-error'), - expected: path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js'), - }) + + function normalizePath (path) { + const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - 1) + return normalizedPath + } + + const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) + const expectedPathOfFastifyError = normalizePath(path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js')) + // Ensure that fastify-error is required from the node_modules directory of the test-project - if (require.resolve('fastify-error') !== path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js')) { + if (actualPathOfFastifyError !== expectedPathOfFastifyError) { throw new Error('fastify-error should be required from the node_modules directory of the test-project') } @@ -130,16 +134,19 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError } = require('fastify-error') - console.log({ - actual: require.resolve('fastify-error'), - expected: path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js'), - }) - - // Ensure that fastify-error is required from the node_modules directory of dep - if (require.resolve('fastify-error') !== path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) { + function normalizePath (path) { + const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - 1) + return normalizedPath + } + + const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) + const expectedPathOfFastifyError = normalizePath(path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) + + // Ensure that fastify-error is required from the node_modules directory of the test-project + if (actualPathOfFastifyError !== expectedPathOfFastifyError) { throw new Error('fastify-error should be required from the node_modules directory of dep') } - + const Boom = createError('Boom', 'Boom', 500) const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom) From a1589b25dc17fcafcab81b7b5edd494af151c249 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:28:50 +0200 Subject: [PATCH 08/20] try to fix windows run --- test/instanceof.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 4fa4d7e..ed57d6a 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -135,7 +135,7 @@ test('ensure that instanceof works accross different installations of the fastif const { createError } = require('fastify-error') function normalizePath (path) { - const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - 1) + const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - (process.platform === 'win32' ? 2 : 1)) return normalizedPath } From 6bf37420fa172befa4a3f6bccab9788ef656bd50 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:30:15 +0200 Subject: [PATCH 09/20] simplify --- test/instanceof.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index ed57d6a..386ab20 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -88,7 +88,7 @@ test('ensure that instanceof works accross different installations of the fastif const { foo } = require('dep') function normalizePath (path) { - const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - 1) + const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-")) return normalizedPath } @@ -135,7 +135,7 @@ test('ensure that instanceof works accross different installations of the fastif const { createError } = require('fastify-error') function normalizePath (path) { - const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-") - (process.platform === 'win32' ? 2 : 1)) + const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-")) return normalizedPath } From ca714c23931c0592e18ae905632fa60785c39282 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:32:47 +0200 Subject: [PATCH 10/20] log more --- test/instanceof.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 386ab20..d0a0b75 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -97,6 +97,8 @@ test('ensure that instanceof works accross different installations of the fastif // Ensure that fastify-error is required from the node_modules directory of the test-project if (actualPathOfFastifyError !== expectedPathOfFastifyError) { + console.error('actualPathOfFastifyError', actualPathOfFastifyError) + console.error('expectedPathOfFastifyError', expectedPathOfFastifyError) throw new Error('fastify-error should be required from the node_modules directory of the test-project') } @@ -144,6 +146,8 @@ test('ensure that instanceof works accross different installations of the fastif // Ensure that fastify-error is required from the node_modules directory of the test-project if (actualPathOfFastifyError !== expectedPathOfFastifyError) { + console.error('actualPathOfFastifyError', actualPathOfFastifyError) + console.error('expectedPathOfFastifyError', expectedPathOfFastifyError) throw new Error('fastify-error should be required from the node_modules directory of dep') } From 53f133d99f046a51410b25465201a53abb6e7794 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:43:12 +0200 Subject: [PATCH 11/20] use lastIndexOf instead of indexOf to avoid issues in GH Runner with Windows --- test/instanceof.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index d0a0b75..fb2f912 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -88,7 +88,7 @@ test('ensure that instanceof works accross different installations of the fastif const { foo } = require('dep') function normalizePath (path) { - const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-")) + const normalizedPath = path.slice(path.lastIndexOf("fastify-error-instanceof-test-")) return normalizedPath } @@ -137,7 +137,7 @@ test('ensure that instanceof works accross different installations of the fastif const { createError } = require('fastify-error') function normalizePath (path) { - const normalizedPath = path.slice(path.indexOf("fastify-error-instanceof-test-")) + const normalizedPath = path.slice(path.lastIndexOf("fastify-error-instanceof-test-")) return normalizedPath } From f25e0b2951856f719cf47b194d3010ac6e7b17ea Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 17:54:44 +0200 Subject: [PATCH 12/20] hope this fixes it --- test/instanceof.test.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index fb2f912..ec13852 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -75,7 +75,9 @@ test('ensure that instanceof works accross different installations of the fastif // └── fastify-error/ // └── index.js - const testCwd = path.resolve(os.tmpdir(), `fastify-error-instanceof-test-${Math.random().toString(36).substring(2, 15)}`) + const testDirectoryPrefix = 'fastify-error-instanceof-test-' + + const testCwd = path.resolve(os.tmpdir(), `${testDirectoryPrefix}${Math.random().toString(36).substring(2, 15)}`) fs.mkdirSync(testCwd, { recursive: true }) // Create the index.js. It will be executed as a forked process, so we need to @@ -87,8 +89,8 @@ test('ensure that instanceof works accross different installations of the fastif const { createError, FastifyError } = require('fastify-error') const { foo } = require('dep') - function normalizePath (path) { - const normalizedPath = path.slice(path.lastIndexOf("fastify-error-instanceof-test-")) + function normalizePath (filePath) { + const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) return normalizedPath } @@ -136,8 +138,8 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError } = require('fastify-error') - function normalizePath (path) { - const normalizedPath = path.slice(path.lastIndexOf("fastify-error-instanceof-test-")) + function normalizePath (filePath) { + const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) return normalizedPath } From 552c4107101fd69c8b8bece4995f6de8f92b706c Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 18:00:12 +0200 Subject: [PATCH 13/20] log more --- test/instanceof.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index ec13852..09ea944 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -90,6 +90,11 @@ test('ensure that instanceof works accross different installations of the fastif const { foo } = require('dep') function normalizePath (filePath) { + console.log('filePath', filePath) + console.log('path.normalize(filePath)', path.normalize(filePath)) + console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) + console.log('filePath.slice(path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}"))', filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}'))) + const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) return normalizedPath } From 5b0e7e7cc9bb2de7c396fda654ec305f9e4e4b11 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 18:02:53 +0200 Subject: [PATCH 14/20] log more --- test/instanceof.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 09ea944..88b2ac2 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -144,6 +144,11 @@ test('ensure that instanceof works accross different installations of the fastif const { createError } = require('fastify-error') function normalizePath (filePath) { + console.log('filePath', filePath) + console.log('path.normalize(filePath)', path.normalize(filePath)) + console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) + console.log('filePath.slice(path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}"))', filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}'))) + const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) return normalizedPath } From 6ab296045486a431d107471c52b781342e326f4c Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 20:48:38 +0200 Subject: [PATCH 15/20] another try to fix the crossplatform issues --- test/instanceof.test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 88b2ac2..74ba534 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -90,6 +90,15 @@ test('ensure that instanceof works accross different installations of the fastif const { foo } = require('dep') function normalizePath (filePath) { + // normalize for cross platform + filePath = filePath.replace(/\\\\/g, '/') + filePath = filePath.replace(/(\\w):/, '/$1') + filePath = filePath.replace(/(\\w+)\\/\\.\\.\\/?/g, '') + filePath = filePath.replace(/^\\.\\//, '') + filePath = filePath.replace(/\\/\\.\\//, '/') + filePath = filePath.replace(/\\/\\.$/, '') + filePath = filePath.replace(/\\/$/, '') + console.log('filePath', filePath) console.log('path.normalize(filePath)', path.normalize(filePath)) console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) @@ -144,6 +153,15 @@ test('ensure that instanceof works accross different installations of the fastif const { createError } = require('fastify-error') function normalizePath (filePath) { + // normalize for cross platform + filePath = filePath.replace(/\\\\/g, '/') + filePath = filePath.replace(/(\\w):/, '/$1') + filePath = filePath.replace(/(\\w+)\\/\\.\\.\\/?/g, '') + filePath = filePath.replace(/^\\.\\//, '') + filePath = filePath.replace(/\\/\\.\\//, '/') + filePath = filePath.replace(/\\/\\.$/, '') + filePath = filePath.replace(/\\/$/, '') + console.log('filePath', filePath) console.log('path.normalize(filePath)', path.normalize(filePath)) console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) From 8e55ffe2c8d5c816f90588735e1c8fbc70182e95 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 20:53:21 +0200 Subject: [PATCH 16/20] another try --- test/instanceof.test.js | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 74ba534..6179072 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -90,22 +90,9 @@ test('ensure that instanceof works accross different installations of the fastif const { foo } = require('dep') function normalizePath (filePath) { - // normalize for cross platform - filePath = filePath.replace(/\\\\/g, '/') - filePath = filePath.replace(/(\\w):/, '/$1') - filePath = filePath.replace(/(\\w+)\\/\\.\\.\\/?/g, '') - filePath = filePath.replace(/^\\.\\//, '') - filePath = filePath.replace(/\\/\\.\\//, '/') - filePath = filePath.replace(/\\/\\.$/, '') - filePath = filePath.replace(/\\/$/, '') - - console.log('filePath', filePath) - console.log('path.normalize(filePath)', path.normalize(filePath)) - console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) - console.log('filePath.slice(path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}"))', filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}'))) - - const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) - return normalizedPath + filePath = path.normalize(filePath) + filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}')) + return filePath } const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) @@ -151,24 +138,11 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError } = require('fastify-error') - + function normalizePath (filePath) { - // normalize for cross platform - filePath = filePath.replace(/\\\\/g, '/') - filePath = filePath.replace(/(\\w):/, '/$1') - filePath = filePath.replace(/(\\w+)\\/\\.\\.\\/?/g, '') - filePath = filePath.replace(/^\\.\\//, '') - filePath = filePath.replace(/\\/\\.\\//, '/') - filePath = filePath.replace(/\\/\\.$/, '') - filePath = filePath.replace(/\\/$/, '') - - console.log('filePath', filePath) - console.log('path.normalize(filePath)', path.normalize(filePath)) - console.log('path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}")', path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) - console.log('filePath.slice(path.normalize(filePath).lastIndexOf("${testDirectoryPrefix}"))', filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}'))) - - const normalizedPath = filePath.slice(path.normalize(filePath).lastIndexOf('${testDirectoryPrefix}')) - return normalizedPath + filePath = path.normalize(filePath) + filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}')) + return filePath } const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) From f59e889789e20698bcffaa569feff31b4fe786a0 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 20:55:13 +0200 Subject: [PATCH 17/20] ignore the first character of testDirectoryPrefix in hope it fixes the issue --- test/instanceof.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 6179072..04d609c 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -91,7 +91,7 @@ test('ensure that instanceof works accross different installations of the fastif function normalizePath (filePath) { filePath = path.normalize(filePath) - filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}')) + filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}') + 1) return filePath } @@ -141,7 +141,7 @@ test('ensure that instanceof works accross different installations of the fastif function normalizePath (filePath) { filePath = path.normalize(filePath) - filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}')) + filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}') + 1) return filePath } From 164d4e2f2c416a147d4ee7c158e535cc7115614d Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 20:59:25 +0200 Subject: [PATCH 18/20] another try --- test/instanceof.test.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/test/instanceof.test.js b/test/instanceof.test.js index 04d609c..e0cb2ed 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -89,14 +89,8 @@ test('ensure that instanceof works accross different installations of the fastif const { createError, FastifyError } = require('fastify-error') const { foo } = require('dep') - function normalizePath (filePath) { - filePath = path.normalize(filePath) - filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}') + 1) - return filePath - } - - const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) - const expectedPathOfFastifyError = normalizePath(path.resolve('${testCwd}', 'node_modules', 'fastify-error', 'index.js')) + const actualPathOfFastifyError = require.resolve('fastify-error') + const expectedPathOfFastifyError = path.resolve('node_modules', 'fastify-error', 'index.js') // Ensure that fastify-error is required from the node_modules directory of the test-project if (actualPathOfFastifyError !== expectedPathOfFastifyError) { @@ -139,14 +133,8 @@ test('ensure that instanceof works accross different installations of the fastif const path = require('node:path') const { createError } = require('fastify-error') - function normalizePath (filePath) { - filePath = path.normalize(filePath) - filePath = filePath.slice(filePath.lastIndexOf('${testDirectoryPrefix}') + 1) - return filePath - } - - const actualPathOfFastifyError = normalizePath(require.resolve('fastify-error')) - const expectedPathOfFastifyError = normalizePath(path.resolve('${testCwd}','node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')) + const actualPathOfFastifyError = require.resolve('fastify-error') + const expectedPathOfFastifyError = path.resolve('node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js') // Ensure that fastify-error is required from the node_modules directory of the test-project if (actualPathOfFastifyError !== expectedPathOfFastifyError) { From 33bb93ea28585bbf58806e4257889820107dbb76 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Wed, 21 May 2025 23:14:44 +0200 Subject: [PATCH 19/20] modify Readme --- README.md | 79 ++++++++++++++++++++++++++++++++++++++++- test/instanceof.test.js | 49 +++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab0b05f..5da62d2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ npm i @fastify/error The module exports a function that you can use for consistent error objects, it takes 4 parameters: -``` +```js createError(code, message [, statusCode [, Base [, captureStackTrace]]]) ``` @@ -58,6 +58,83 @@ new CustomError('world') new CustomError(1) ``` +### instanceof + +All errors created with `createError` will be instances of the base error constructor you provided, or `Error` if none was provided. + +```js +const createError = require('@fastify/error') +const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) +const customError = new CustomError('world') + +console.log(customError instanceof CustomError) // true +console.log(customError instanceof TypeError) // true +console.log(customError instanceof Error) // true +``` + +All instantiated errors will be instances of the `FastifyError` class. The `FastifyError` class can be required from the module directly. + +```js +const { createError, FastifyError } = require('@fastify/error') +const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) +const customError = new CustomError('world') + +console.log(customError instanceof FastifyError) // true +``` + +It is possible to create a `FastifyError` that extends another `FastifyError`, created by `createError`, while instanceof working correctly. + +```js +const { createError, FastifyError } = require('@fastify/error') + +const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) +const ChildCustomError = createError('CHILD_ERROR_CODE', 'Hello %s', 500, CustomError) + +const customError = new ChildCustomError('world') + +console.log(customError instanceof ChildCustomError) // true +console.log(customError instanceof CustomError) // true +console.log(customError instanceof FastifyError) // true +console.log(customError instanceof TypeError) // true +console.log(customError instanceof Error) // true +``` + +If `fastify-error` is installed multiple times as direct and/or transitive dependency, it is ensured that Errors created with `createError` are working with the `instanceof` operator correctly cross the `fastify-error` installation, as long the code, e.g. `FST_ERR_CUSTOM_ERROR`, is the same. + +```js +const { createError, FastifyError } = require('@fastify/error') + +// CustomError from `@fastify/some-plugin` is created with `createError` and +// has its own `@fastify/error` installation as dependency. CustomError has +// FST_ERR_CUSTOM_ERROR as code. +const { CustomError: CustomErrorFromPlugin } = require('@fastify/some-plugin') + +const CustomError = createError('FST_ERR_CUSTOM_ERROR', 'Hello %s', 500) + +const customError = new CustomError('world') +const customErrorFromPlugin = new CustomErrorFromPlugin('world') + +console.log(customError instanceof CustomError) // true +console.log(customError instanceof CustomErrorFromPlugin) // true +console.log(customErrorFromPlugin instanceof CustomError) // true +console.log(customErrorFromPlugin instanceof CustomErrorFromPlugin) // true +``` + +Changing the code of an instantiated Error will not change the result of the `instanceof` operator. + +```js +const { createError, FastifyError } = require('@fastify/error') + +const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) +const AnotherCustomError = createError('ANOTHER_ERROR_CODE', 'Hello %s', 500, CustomError) + +const customError = new CustomError('world') +customError.code = 'ANOTHER_ERROR_CODE' + +console.log(customError instanceof CustomError) // true +console.log(customError instanceof AnotherCustomError) // false +``` + ## License Licensed under [MIT](./LICENSE). diff --git a/test/instanceof.test.js b/test/instanceof.test.js index e0cb2ed..34d56fb 100644 --- a/test/instanceof.test.js +++ b/test/instanceof.test.js @@ -7,6 +7,55 @@ const os = require('node:os') const test = require('node:test') const { createError, FastifyError } = require('..') +test('Readme: All errors created with `createError` will be instances of the base error constructor you provided, or `Error` if none was provided.', (t) => { + t.plan(3) + + const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) + const customError = new CustomError('world') + + t.assert.ok(customError instanceof CustomError) + t.assert.ok(customError instanceof TypeError) + t.assert.ok(customError instanceof Error) +}) + +test('Readme: All instantiated errors will be instances of the `FastifyError` class. The `FastifyError` class can be required from the module directly.', (t) => { + t.plan(1) + + const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) + const customError = new CustomError('world') + + t.assert.ok(customError instanceof FastifyError) +}) + +test('Readme: It is possible to create a `FastifyError` that extends another `FastifyError`, created by `createError`, while instanceof working correctly.', (t) => { + t.plan(5) + + const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) + const ChildCustomError = createError('CHILD_ERROR_CODE', 'Hello %s', 500, CustomError) + + const customError = new ChildCustomError('world') + + t.assert.ok(customError instanceof ChildCustomError) + t.assert.ok(customError instanceof CustomError) + t.assert.ok(customError instanceof FastifyError) + t.assert.ok(customError instanceof TypeError) + t.assert.ok(customError instanceof Error) +}) + +test('Readme: Changing the code of an instantiated Error will not change the result of the `instanceof` operator.', (t) => { + t.plan(3) + + const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError) + const AnotherCustomError = createError('ANOTHER_ERROR_CODE', 'Hello %s', 500, CustomError) + + const customError = new CustomError('world') + customError.code = 'ANOTHER_ERROR_CODE' + + t.assert.ok(customError instanceof CustomError) + t.assert.ok(customError instanceof AnotherCustomError === false) + t.assert.ok(customError instanceof FastifyError) +}) + test('check if createError creates an Error which is instanceof Error', (t) => { t.plan(3) From 0f1714ed6015fc5d78973875bed7d00f871748e4 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Thu, 22 May 2025 14:25:53 +0200 Subject: [PATCH 20/20] Apply suggestions from code review Co-authored-by: Frazer Smith Signed-off-by: Aras Abbasi --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5da62d2..94814fe 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ console.log(customError instanceof TypeError) // true console.log(customError instanceof Error) // true ``` -All instantiated errors will be instances of the `FastifyError` class. The `FastifyError` class can be required from the module directly. +All instantiated errors are instances of the `FastifyError` class, which can be required directly from the module. ```js const { createError, FastifyError } = require('@fastify/error') @@ -82,7 +82,7 @@ const customError = new CustomError('world') console.log(customError instanceof FastifyError) // true ``` -It is possible to create a `FastifyError` that extends another `FastifyError`, created by `createError`, while instanceof working correctly. +A `FastifyError` created by `createError` can extend another `FastifyError` while maintaining correct `instanceof` behavior. ```js const { createError, FastifyError } = require('@fastify/error') @@ -99,7 +99,7 @@ console.log(customError instanceof TypeError) // true console.log(customError instanceof Error) // true ``` -If `fastify-error` is installed multiple times as direct and/or transitive dependency, it is ensured that Errors created with `createError` are working with the `instanceof` operator correctly cross the `fastify-error` installation, as long the code, e.g. `FST_ERR_CUSTOM_ERROR`, is the same. +If `fastify-error` is installed multiple times directly or as a transitive dependency, `instanceof` checks for errors created by `createError` will still work correctly across these installations, as long as their error codes (e.g., `FST_ERR_CUSTOM_ERROR`) are identical. ```js const { createError, FastifyError } = require('@fastify/error')